Crossfire Server, Trunk
CRECombatSimulator.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2022 the Crossfire Development Team
5  *
6  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
7  * welcome to redistribute it under certain conditions. For details, please
8  * see COPYING and LICENSE.
9  *
10  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
11  */
12 
13 #include "CRECombatSimulator.h"
14 #include "CREPixmap.h"
15 
16 #include <global.h>
17 #include <sproto.h>
18 #include "assets.h"
19 #include "AssetsManager.h"
21 
23 {
24  QGridLayout* layout = new QGridLayout(this);
25  int line = 0;
26 
27  layout->addWidget(new QLabel(tr("First fighter:"), this), line, 0);
28  myFirst = new ArchetypeComboBox(this, false);
29  layout->addWidget(myFirst, line++, 1);
30 
31  layout->addWidget(new QLabel(tr("Second fighter:"), this), line, 0);
32  mySecond = new ArchetypeComboBox(this, false);
33  layout->addWidget(mySecond, line++, 1);
34 
35  layout->addWidget(new QLabel(tr("Number of fights:"), this), line, 0);
36  myCombats = new QSpinBox(this);
37  myCombats->setMinimum(1);
38  myCombats->setMaximum(10000);
39  layout->addWidget(myCombats, line++, 1);
40 
41  layout->addWidget(new QLabel(tr("Maximum number of rounds:"), this), line, 0);
42  myMaxRounds = new QSpinBox(this);
43  myMaxRounds->setMinimum(1);
44  myMaxRounds->setMaximum(10000);
45  myMaxRounds->setValue(500);
46  layout->addWidget(myMaxRounds, line++, 1);
47 
48  myResultLabel = new QLabel(tr("Combat result:"), this);
49  myResultLabel->setVisible(false);
50  layout->addWidget(myResultLabel, line++, 0, 1, 2);
51  myResult = new QLabel(this);
52  myResult->setVisible(false);
53  layout->addWidget(myResult, line++, 0, 1, 2);
54 
55  QDialogButtonBox* box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close, Qt::Horizontal, this);
56  layout->addWidget(box, line++, 0, 1, 2);
57  connect(box, SIGNAL(rejected()), this, SLOT(reject()));
58  connect(box, SIGNAL(accepted()), this, SLOT(fight()));
59 
60  setWindowTitle(tr("Combat simulator"));
61 }
62 
64 {
65 }
66 
67 void CRECombatSimulator::fight(const archetype* first, const archetype* second)
68 {
69  int limit = myMaxRounds->value();
70  object* obfirst = object_create_arch(const_cast<archetype *>(first));
71  object* obsecond = object_create_arch(const_cast<archetype *>(second));
72  tag_t tagfirst = obfirst->count;
73  tag_t tagsecond = obsecond->count;
74 
75  // make a big map so large monsters are ok in map
76  mapstruct* test_map = get_empty_map(50, 50);
77 
78  // insert shifted for monsters like titans who have parts with negative values
79  obfirst = object_insert_in_map_at(obfirst, test_map, NULL, 0, 12, 12);
80  obsecond = object_insert_in_map_at(obsecond, test_map, NULL, 0, 37, 37);
81 
82  while (limit-- > 0 && obfirst->stats.hp >= 0 && obsecond->stats.hp >= 0)
83  {
84  if (obfirst->speed_left > 0) {
85  --obfirst->speed_left;
86  monster_do_living(obfirst);
87  if (obfirst->stats.hp > myFirstMaxHp)
88  myFirstMaxHp = obfirst->stats.hp;
89 
90  attack_ob(obsecond, obfirst);
91  if (object_was_destroyed(obsecond, tagsecond))
92  break;
93  if (obsecond->stats.hp < mySecondMinHp && obsecond->stats.hp > 0)
94  mySecondMinHp = obsecond->stats.hp;
95  }
96 
97  if (obsecond->speed_left > 0) {
98  --obsecond->speed_left;
99  monster_do_living(obsecond);
100  if (obsecond->stats.hp > mySecondMaxHp)
101  mySecondMaxHp = obsecond->stats.hp;
102 
103  attack_ob(obfirst, obsecond);
104  if (object_was_destroyed(obfirst, tagfirst))
105  break;
106  if (obfirst->stats.hp < myFirstMinHp && obfirst->stats.hp > 0)
107  myFirstMinHp = obfirst->stats.hp;
108  }
109 
110  if (obfirst->speed_left <= 0)
111  obfirst->speed_left += FABS(obfirst->speed);
112  if (obsecond->speed_left <= 0)
113  obsecond->speed_left += FABS(obsecond->speed);
114  }
115 
116  if (limit > 0)
117  {
118  if (obfirst->stats.hp < 0)
120  else
122  }
123 
124  if (!object_was_destroyed(obfirst, tagfirst))
125  {
126  object_remove(obfirst);
127  object_free(obfirst, 0);
128  }
129  if (!object_was_destroyed(obsecond, tagsecond))
130  {
131  object_remove(obsecond);
132  object_free(obsecond, 0);
133  }
135 }
136 
138 {
139  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
140 
141  myFirstVictories = 0;
142  mySecondVictories = 0;
143 
144  const archetype* first = myFirst->arch();
145  const archetype* second = mySecond->arch();
146 
147  /*
148  * Set min and max hp here, in case a monster doesn't ever get attacked
149  * Example as of the time of writing is cherub vs. cherub
150  * without this fix, the first cherub had maxhp of 10000 and minhp of -1
151  *
152  * So, temporaily create the objects to then determine what the maxhp is for
153  * each object from the archetypes.
154  */
155  object* obfirst = object_create_arch(const_cast<archetype *>(first));
156  object* obsecond = object_create_arch(const_cast<archetype *>(second));
157 
158  myFirstMinHp = obfirst->stats.maxhp;
159  myFirstMaxHp = obfirst->stats.maxhp;
160  mySecondMinHp = obsecond->stats.maxhp;
161  mySecondMaxHp = obsecond->stats.maxhp;
162 
163  /*
164  * Then, free the objects since this is done.
165  */
166  object_free(obfirst, 0);
167  object_free(obsecond, 0);
168 
169  int count = myCombats->value();
170  while (count-- > 0)
171  {
172  fight(first, second);
173  }
174 
175  myResult->setText(tr("Draw: %1 fights\n%2 victories: %3 (max hp: %4, min hp: %5)\n%6 victories: %7 (max hp: %8, min hp: %9)")
176  .arg(myCombats->value() - myFirstVictories - mySecondVictories)
177  .arg(first->name).arg(myFirstVictories).arg(myFirstMaxHp).arg(myFirstMinHp)
178  .arg(second->name).arg(mySecondVictories).arg(mySecondMaxHp).arg(mySecondMinHp));
179 
180  myResultLabel->setVisible(true);
181  myResult->setVisible(true);
182 
183  QApplication::restoreOverrideCursor();
184 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
global.h
CRECombatSimulator::fight
void fight()
Definition: CRECombatSimulator.cpp:137
living::maxhp
int16_t maxhp
Definition: living.h:41
layout
Definition: main.cpp:84
FABS
#define FABS(x)
Definition: define.h:22
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.cpp:843
test_map
mapstruct * test_map
Definition: comet_perf.cpp:74
AssetsManager.h
object::speed
float speed
Definition: object.h:337
CRECombatSimulator::mySecondMaxHp
int mySecondMaxHp
Definition: CRECombatSimulator.h:53
object::speed_left
float speed_left
Definition: object.h:338
CRECombatSimulator::myCombats
QSpinBox * myCombats
Definition: CRECombatSimulator.h:43
object::count
tag_t count
Definition: object.h:307
monster_do_living
void monster_do_living(object *op)
Definition: monster.cpp:719
ArchetypeComboBox::arch
const archetype arch
Definition: ArchetypeComboBox.h:26
CRECombatSimulator::myFirstVictories
int myFirstVictories
Definition: CRECombatSimulator.h:48
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
CRECombatSimulator::CRECombatSimulator
CRECombatSimulator()
Definition: CRECombatSimulator.cpp:22
CRECombatSimulator::myResultLabel
QLabel * myResultLabel
Definition: CRECombatSimulator.h:45
CRECombatSimulator.h
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:298
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1592
ArchetypeComboBox
Definition: ArchetypeComboBox.h:23
say.box
box
Definition: say.py:152
free_map
void free_map(mapstruct *m)
Definition: map.cpp:1653
disinfect.count
int count
Definition: disinfect.py:7
tag_t
uint32_t tag_t
Definition: object.h:14
archetype
Definition: object.h:483
sproto.h
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2100
CRECombatSimulator::~CRECombatSimulator
virtual ~CRECombatSimulator()
Definition: CRECombatSimulator.cpp:63
mapstruct
Definition: map.h:313
ArchetypeComboBox.h
assets.h
CRECombatSimulator::myFirstMaxHp
int myFirstMaxHp
Definition: CRECombatSimulator.h:50
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
CRECombatSimulator::mySecond
ArchetypeComboBox * mySecond
Definition: CRECombatSimulator.h:42
CRECombatSimulator::myMaxRounds
QSpinBox * myMaxRounds
Definition: CRECombatSimulator.h:44
CRECombatSimulator::myFirstMinHp
int myFirstMinHp
Definition: CRECombatSimulator.h:49
CRECombatSimulator::myFirst
ArchetypeComboBox * myFirst
Definition: CRECombatSimulator.h:41
CRECombatSimulator::mySecondVictories
int mySecondVictories
Definition: CRECombatSimulator.h:51
CRECombatSimulator::myResult
QLabel * myResult
Definition: CRECombatSimulator.h:46
archetype::name
sstring name
Definition: object.h:484
object::stats
living stats
Definition: object.h:378
CRECombatSimulator::mySecondMinHp
int mySecondMinHp
Definition: CRECombatSimulator.h:52
attack_ob
int attack_ob(object *op, object *hitter)
Definition: attack.cpp:937
connect
Definition: connect.py:1
CREPixmap.h
living::hp
int16_t hp
Definition: living.h:40