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 extern "C" {
17 #include <global.h>
18 #include <sproto.h>
19 }
20 #include "assets.h"
21 #include "AssetsManager.h"
23 
25 {
26  QGridLayout* layout = new QGridLayout(this);
27  int line = 0;
28 
29  layout->addWidget(new QLabel(tr("First fighter:"), this), line, 0);
30  myFirst = new ArchetypeComboBox(this, false);
31  layout->addWidget(myFirst, line++, 1);
32 
33  layout->addWidget(new QLabel(tr("Second fighter:"), this), line, 0);
34  mySecond = new ArchetypeComboBox(this, false);
35  layout->addWidget(mySecond, line++, 1);
36 
37  layout->addWidget(new QLabel(tr("Number of fights:"), this), line, 0);
38  myCombats = new QSpinBox(this);
39  myCombats->setMinimum(1);
40  myCombats->setMaximum(10000);
41  layout->addWidget(myCombats, line++, 1);
42 
43  layout->addWidget(new QLabel(tr("Maximum number of rounds:"), this), line, 0);
44  myMaxRounds = new QSpinBox(this);
45  myMaxRounds->setMinimum(1);
46  myMaxRounds->setMaximum(10000);
47  myMaxRounds->setValue(500);
48  layout->addWidget(myMaxRounds, line++, 1);
49 
50  myResultLabel = new QLabel(tr("Combat result:"), this);
51  myResultLabel->setVisible(false);
52  layout->addWidget(myResultLabel, line++, 0, 1, 2);
53  myResult = new QLabel(this);
54  myResult->setVisible(false);
55  layout->addWidget(myResult, line++, 0, 1, 2);
56 
57  QDialogButtonBox* box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close, Qt::Horizontal, this);
58  layout->addWidget(box, line++, 0, 1, 2);
59  connect(box, SIGNAL(rejected()), this, SLOT(reject()));
60  connect(box, SIGNAL(accepted()), this, SLOT(fight()));
61 
62  setWindowTitle(tr("Combat simulator"));
63 }
64 
66 {
67 }
68 
69 void CRECombatSimulator::fight(const archetype* first, const archetype* second)
70 {
71  int limit = myMaxRounds->value();
72  object* obfirst = object_create_arch(const_cast<archetype *>(first));
73  object* obsecond = object_create_arch(const_cast<archetype *>(second));
74  tag_t tagfirst = obfirst->count;
75  tag_t tagsecond = obsecond->count;
76 
77  // make a big map so large monsters are ok in map
78  mapstruct* test_map = get_empty_map(50, 50);
79 
80  // insert shifted for monsters like titans who have parts with negative values
81  obfirst = object_insert_in_map_at(obfirst, test_map, NULL, 0, 12, 12);
82  obsecond = object_insert_in_map_at(obsecond, test_map, NULL, 0, 37, 37);
83 
84  while (limit-- > 0 && obfirst->stats.hp >= 0 && obsecond->stats.hp >= 0)
85  {
86  if (obfirst->speed_left > 0) {
87  --obfirst->speed_left;
88  monster_do_living(obfirst);
89  if (obfirst->stats.hp > myFirstMaxHp)
90  myFirstMaxHp = obfirst->stats.hp;
91 
92  attack_ob(obsecond, obfirst);
93  if (object_was_destroyed(obsecond, tagsecond))
94  break;
95  if (obsecond->stats.hp < mySecondMinHp && obsecond->stats.hp > 0)
96  mySecondMinHp = obsecond->stats.hp;
97  }
98 
99  if (obsecond->speed_left > 0) {
100  --obsecond->speed_left;
101  monster_do_living(obsecond);
102  if (obsecond->stats.hp > mySecondMaxHp)
103  mySecondMaxHp = obsecond->stats.hp;
104 
105  attack_ob(obfirst, obsecond);
106  if (object_was_destroyed(obfirst, tagfirst))
107  break;
108  if (obfirst->stats.hp < myFirstMinHp && obfirst->stats.hp > 0)
109  myFirstMinHp = obfirst->stats.hp;
110  }
111 
112  if (obfirst->speed_left <= 0)
113  obfirst->speed_left += FABS(obfirst->speed);
114  if (obsecond->speed_left <= 0)
115  obsecond->speed_left += FABS(obsecond->speed);
116  }
117 
118  if (limit > 0)
119  {
120  if (obfirst->stats.hp < 0)
122  else
124  }
125 
126  if (!object_was_destroyed(obfirst, tagfirst))
127  {
128  object_remove(obfirst);
129  object_free(obfirst, 0);
130  }
131  if (!object_was_destroyed(obsecond, tagsecond))
132  {
133  object_remove(obsecond);
134  object_free(obsecond, 0);
135  }
137 }
138 
140 {
141  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
142 
143  myFirstVictories = 0;
144  mySecondVictories = 0;
145 
146  const archetype* first = myFirst->arch();
147  const archetype* second = mySecond->arch();
148 
149  /*
150  * Set min and max hp here, in case a monster doesn't ever get attacked
151  * Example as of the time of writing is cherub vs. cherub
152  * without this fix, the first cherub had maxhp of 10000 and minhp of -1
153  *
154  * So, temporaily create the objects to then determine what the maxhp is for
155  * each object from the archetypes.
156  */
157  object* obfirst = object_create_arch(const_cast<archetype *>(first));
158  object* obsecond = object_create_arch(const_cast<archetype *>(second));
159 
160  myFirstMinHp = obfirst->stats.maxhp;
161  myFirstMaxHp = obfirst->stats.maxhp;
162  mySecondMinHp = obsecond->stats.maxhp;
163  mySecondMaxHp = obsecond->stats.maxhp;
164 
165  /*
166  * Then, free the objects since this is done.
167  */
168  object_free(obfirst, 0);
169  object_free(obsecond, 0);
170 
171  int count = myCombats->value();
172  while (count-- > 0)
173  {
174  fight(first, second);
175  }
176 
177  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)")
178  .arg(myCombats->value() - myFirstVictories - mySecondVictories)
179  .arg(first->name).arg(myFirstVictories).arg(myFirstMaxHp).arg(myFirstMinHp)
180  .arg(second->name).arg(mySecondVictories).arg(mySecondMaxHp).arg(mySecondMinHp));
181 
182  myResultLabel->setVisible(true);
183  myResult->setVisible(true);
184 
185  QApplication::restoreOverrideCursor();
186 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
global.h
CRECombatSimulator::fight
void fight()
Definition: CRECombatSimulator.cpp:139
object_free
void object_free(object *ob, int flags)
Definition: object.c:1578
object_remove
void object_remove(object *op)
Definition: object.c:1819
layout
Definition: main.c:85
FABS
#define FABS(x)
Definition: define.h:22
obj::count
tag_t count
Definition: object.h:302
AssetsManager.h
liv::maxhp
int16_t maxhp
Definition: living.h:41
CRECombatSimulator::mySecondMaxHp
int mySecondMaxHp
Definition: CRECombatSimulator.h:55
CRECombatSimulator::myCombats
QSpinBox * myCombats
Definition: CRECombatSimulator.h:45
liv::hp
int16_t hp
Definition: living.h:40
monster_do_living
void monster_do_living(object *op)
Definition: monster.c:715
ArchetypeComboBox::arch
const archetype arch
Definition: ArchetypeComboBox.h:28
CRECombatSimulator::myFirstVictories
int myFirstVictories
Definition: CRECombatSimulator.h:50
archt
Definition: object.h:469
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
CRECombatSimulator::CRECombatSimulator
CRECombatSimulator()
Definition: CRECombatSimulator.cpp:24
CRECombatSimulator::myResultLabel
QLabel * myResultLabel
Definition: CRECombatSimulator.h:47
CRECombatSimulator.h
obj::speed_left
float speed_left
Definition: object.h:333
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:301
ArchetypeComboBox
Definition: ArchetypeComboBox.h:25
say.box
box
Definition: say.py:152
disinfect.count
int count
Definition: disinfect.py:7
free_map
void free_map(mapstruct *m)
Definition: map.c:1676
obj::speed
float speed
Definition: object.h:332
tag_t
uint32_t tag_t
Definition: object.h:12
sproto.h
mapdef
Definition: map.h:317
CRECombatSimulator::~CRECombatSimulator
virtual ~CRECombatSimulator()
Definition: CRECombatSimulator.cpp:65
test_map
mapstruct * test_map
Definition: comet_perf.c:74
obj::stats
living stats
Definition: object.h:373
ArchetypeComboBox.h
assets.h
CRECombatSimulator::myFirstMaxHp
int myFirstMaxHp
Definition: CRECombatSimulator.h:52
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.c:2080
CRECombatSimulator::mySecond
ArchetypeComboBox * mySecond
Definition: CRECombatSimulator.h:44
CRECombatSimulator::myMaxRounds
QSpinBox * myMaxRounds
Definition: CRECombatSimulator.h:46
CRECombatSimulator::myFirstMinHp
int myFirstMinHp
Definition: CRECombatSimulator.h:51
CRECombatSimulator::myFirst
ArchetypeComboBox * myFirst
Definition: CRECombatSimulator.h:43
CRECombatSimulator::mySecondVictories
int mySecondVictories
Definition: CRECombatSimulator.h:53
archt::name
sstring name
Definition: object.h:470
CRECombatSimulator::myResult
QLabel * myResult
Definition: CRECombatSimulator.h:48
CRECombatSimulator::mySecondMinHp
int mySecondMinHp
Definition: CRECombatSimulator.h:54
attack_ob
int attack_ob(object *op, object *hitter)
Definition: attack.c:919
connect
Definition: connect.py:1
CREPixmap.h
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.c:869