1 // Copyright (C) 2000, 2001, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2005 Andrea Paternesi
4 // Copyright (C) 2007, 2008, 2011, 2014, 2015, 2017 Ben Asselstine
5 // Copyright (C) 2007, 2008 Ole Laursen
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 // 02110-1301, USA.
21
22 #include <iostream>
23 #include <sstream>
24 #include "army.h"
25 #include "armyprodbase.h"
26 #include "armyproto.h"
27 #include "armysetlist.h"
28 #include "counter.h"
29 #include "xmlhelper.h"
30 #include "stacklist.h"
31 #include "templelist.h"
32 #include "ucompose.hpp"
33 #include "Tile.h"
34 #include "player.h"
35
36 Glib::ustring Army::d_tag = "army";
37
38 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
39 #define debug(x)
40
41 sigc::signal<void, Army*> Army::sdying;
42
Army(const Army & a,Player * p)43 Army::Army(const Army& a, Player* p)
44 : ArmyBase(a), UniquelyIdentified(a), Ownable(p), sigc::trackable(a),
45 d_type_id(a.d_type_id), d_armyset(a.d_armyset), d_max_hp(a.d_max_hp),
46 d_max_moves_multiplier(a.d_max_moves_multiplier),
47 d_max_moves_rest_bonus(a.d_max_moves_rest_bonus),
48 d_ship(a.d_ship), d_hp(a.d_hp), d_moves(a.d_moves), d_xp(a.d_xp),
49 d_level(a.d_level), d_battles_number(a.d_battles_number),
50 d_number_hashit(a.d_number_hashit),
51 d_number_hasbeenhit(a.d_number_hasbeenhit),
52 d_visitedTemples(a.d_visitedTemples)
53 {
54 for(int i = 0; i < 3; i++)
55 d_medal_bonus[i] = a.d_medal_bonus[i];
56 }
57
Army(const ArmyProto & a,Player * p)58 Army::Army(const ArmyProto& a, Player* p)
59 :ArmyBase(a), UniquelyIdentified(), Ownable(p),
60 d_type_id(a.getId()), d_armyset(a.getArmyset()),
61 d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
62 d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
63 d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
64 {
65 for(int i = 0; i < 3; i++)
66 d_medal_bonus[i] = 0;
67 d_visitedTemples.clear();
68 }
69
Army(const ArmyProto & a,guint32 id,Player * p)70 Army::Army(const ArmyProto& a, guint32 id, Player *p)
71 :ArmyBase(a), UniquelyIdentified(id), Ownable(p),
72 d_type_id(a.getId()), d_armyset(a.getArmyset()),
73 d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
74 d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
75 d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
76 {
77 for(int i = 0; i < 3; i++)
78 d_medal_bonus[i] = 0;
79 d_visitedTemples.clear();
80 }
81
Army(const ArmyProdBase & a,guint32 id,Player * p)82 Army::Army(const ArmyProdBase& a, guint32 id, Player *p)
83 :ArmyBase(a), UniquelyIdentified(id), Ownable(p),
84 d_type_id(a.getTypeId()), d_armyset(a.getArmyset()),
85 d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
86 d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
87 d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
88 {
89 for(int i = 0; i < 3; i++)
90 d_medal_bonus[i] = 0;
91 d_visitedTemples.clear();
92 }
93
createNonUniqueArmy(const ArmyProto & a,Player * player)94 Army* Army::createNonUniqueArmy(const ArmyProto& a, Player *player)
95 {
96 return new Army(a, (guint32) 0, player);
97 }
98
createNonUniqueArmy(const ArmyProdBase & a,Player * player)99 Army* Army::createNonUniqueArmy(const ArmyProdBase& a, Player *player)
100 {
101 return new Army(a, (guint32) 0, player);
102 }
103
Army(const ArmyProdBase & a,Player * p)104 Army::Army(const ArmyProdBase& a, Player* p)
105 :ArmyBase(a), UniquelyIdentified(), Ownable(p),
106 d_type_id(a.getTypeId()), d_armyset(a.getArmyset()),
107 d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
108 d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
109 d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
110 {
111 for(int i = 0; i < 3; i++)
112 d_medal_bonus[i] = 0;
113 d_visitedTemples.clear();
114 }
115
Army()116 Army::Army()
117 :ArmyBase(), UniquelyIdentified(), Ownable((Player *)0),
118 d_type_id(0), d_armyset(0), d_max_hp(2), d_max_moves_multiplier(1),
119 d_max_moves_rest_bonus(0), d_ship(false), d_hp(2), d_moves(0), d_xp(0),
120 d_level(0), d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
121 {
122 d_visitedTemples.clear();
123 }
124
Army(XML_Helper * helper)125 Army::Army(XML_Helper* helper)
126 :ArmyBase(helper), UniquelyIdentified(helper), Ownable((XML_Helper*) 0),
127 d_type_id(0), d_armyset(0), d_max_hp(2), d_max_moves_multiplier(1),
128 d_max_moves_rest_bonus(0), d_ship(false), d_hp(2), d_moves(0), d_xp(0),
129 d_level(0), d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
130 {
131 //d_owner is not read in here. it is set to the owner of the stack
132 //in stack.cpp
133 d_visitedTemples.clear();
134
135 int ival = -1;
136 //get the information which army we are
137 helper->getData(d_type_id, "type");
138 helper->getData(d_armyset, "armyset");
139
140 helper->getData(d_hp, "hp");
141 helper->getData(d_ship, "ship");
142 helper->getData(d_moves, "moves");
143 helper->getData(d_max_moves_multiplier, "max_moves_multiplier");
144 helper->getData(d_xp, "xp");
145 helper->getData(d_level, "level");
146
147 Glib::ustring medals;
148 std::stringstream smedals;
149 bool val;
150
151 helper->getData(medals, "medals");
152 smedals.str(medals);
153
154 for(int i=0;i<3;i++)
155 {
156 smedals >> val;
157 d_medal_bonus[i]=val;
158 debug("ARMY-XML-CONSTRUCTOR medalsbonus[" << i << "]=" << d_medal_bonus[i])
159 }
160
161 helper->getData(d_battles_number, "battlesnumber");
162
163 Glib::ustring temples;
164 std::stringstream stemples;
165 helper->getData(temples, "visited_temples");
166 stemples.str(temples);
167
168 while (stemples.eof() == false)
169 {
170 ival = -1;
171 stemples >> ival;
172 if (ival != -1)
173 d_visitedTemples.push_front(ival);
174 }
175 }
176
~Army()177 Army::~Army()
178 {
179 if (d_unique)
180 sdying.emit(this);
181 }
182
setStat(Army::Stat stat,guint32 value)183 void Army::setStat(Army::Stat stat, guint32 value)
184 {
185 switch (stat)
186 {
187 case STRENGTH:
188 d_strength = value;
189 if (d_strength > MAX_ARMY_STRENGTH)
190 d_strength = MAX_ARMY_STRENGTH;
191 break;
192 case HP:
193 d_max_hp = value;
194 if (d_hp > d_max_hp)
195 d_hp = value;
196 break;
197 case MOVES:
198 d_max_moves = value;
199 if (d_moves > d_max_moves)
200 d_moves = value;
201 break;
202 case MOVES_MULTIPLIER:
203 d_max_moves_multiplier = value;
204 break;
205 case MOVE_BONUS: d_move_bonus = value;
206 break;
207 case ARMY_BONUS: d_army_bonus = value;
208 break;
209 case SIGHT: d_sight = value;
210 break;
211 case SHIP: value == 0 ? d_ship = false : d_ship = true;
212 break;
213 case BOAT_STRENGTH:
214 break;
215 }
216 }
217
getStat(Stat stat,bool modified) const218 guint32 Army::getStat(Stat stat, bool modified) const
219 {
220 switch (stat)
221 {
222 case STRENGTH:
223 return d_strength;
224 case HP:
225 return d_max_hp;
226 case MOVES:
227 {
228 if (modified)
229 return (d_max_moves + d_max_moves_rest_bonus) * d_max_moves_multiplier;
230 else
231 return d_max_moves;
232 }
233 case MOVE_BONUS:
234 return d_move_bonus;
235 case ARMY_BONUS:
236 return d_army_bonus;
237 case SIGHT:
238 return d_sight;
239 case SHIP:
240 return d_ship;
241 case MOVES_MULTIPLIER:
242 return d_max_moves_multiplier;
243 case BOAT_STRENGTH:
244 {
245 if (d_ship)
246 {
247 if (d_strength >= MAX_BOAT_STRENGTH)
248 return MAX_BOAT_STRENGTH;
249 else
250 return d_strength;
251 }
252 else
253 return d_strength;
254 }
255 }
256
257 // should never come to this
258 return 0;
259 }
260
resetMoves()261 void Army::resetMoves()
262 {
263 switch (d_moves)
264 {
265 case 0: d_max_moves_rest_bonus = 0; break;
266 case 1: d_max_moves_rest_bonus = 1; break;
267 case 2: d_max_moves_rest_bonus = 2; break;
268 default: d_max_moves_rest_bonus = 2; break;
269 }
270 if (d_ship)
271 d_moves = MAX_BOAT_MOVES;
272 else
273 d_moves = getStat(MOVES);
274 }
275
276 /* is this temple one we've already visited? */
bless(Temple * temple)277 bool Army::bless(Temple *temple)
278 {
279 bool visited = false;
280
281 if (!temple)
282 return false;
283
284 for (auto it: d_visitedTemples)
285 if (it == temple->getId())
286 visited = true;
287
288 if (visited == false) /* no? increase strength */
289 {
290 d_visitedTemples.push_back(temple->getId());
291 setStat(STRENGTH, d_strength + 1);
292 }
293 return !visited;
294 }
295
296
heal(guint32 hp)297 void Army::heal(guint32 hp)
298 {
299 if (hp == 0)
300 {
301 // if no hp are specified, we assume that the healing at the end of
302 // the turn takes place. In this case the algorithm is: Heal 10%
303 // plus 1HP for each point of vitality above 5 (or one less for each
304 // point below 5), heal a minimum of 1 HP per turn
305 hp = getStat(HP)/10;
306 if (hp <= 5)
307 hp = 1;
308 else
309 hp += 5;
310 }
311
312 d_hp += hp;
313 if (d_hp > getStat(HP))
314 d_hp = getStat(HP);
315 }
316
damage(guint32 damageDone)317 bool Army::damage(guint32 damageDone)
318 {
319 if (damageDone >= d_hp)
320 d_hp = 0;
321 else
322 d_hp -= damageDone;
323 return (d_hp == 0);
324 }
325
decrementMoves(guint32 moves)326 void Army::decrementMoves(guint32 moves)
327 {
328 if (moves >= d_moves)
329 d_moves = 0;
330 else
331 d_moves -= moves;
332 }
333
incrementMoves(guint32 moves)334 void Army::incrementMoves(guint32 moves)
335 {
336 d_moves += moves;
337 }
338
gainXp(double n)339 void Army::gainXp(double n)
340 {
341 d_xp += n;
342 }
343
save(XML_Helper * helper) const344 bool Army::save(XML_Helper* helper) const
345 {
346 bool retval = true;
347
348 retval &= helper->openTag(Army::d_tag);
349 retval &= saveData(helper);
350 retval &= helper->closeTag();
351
352 return retval;
353 }
354
saveData(XML_Helper * helper) const355 bool Army::saveData(XML_Helper* helper) const
356 {
357 bool retval = true;
358
359 retval &= ArmyBase::saveData(helper);
360 retval &= helper->saveData("id", d_id);
361 retval &= helper->saveData("armyset", d_armyset);
362 retval &= helper->saveData("type", d_type_id);
363 retval &= helper->saveData("hp", d_hp);
364 retval &= helper->saveData("ship", d_ship);
365 retval &= helper->saveData("moves", d_moves);
366 retval &= helper->saveData("xp", d_xp);
367 retval &= helper->saveData("max_moves_multiplier",
368 d_max_moves_multiplier);
369 retval &= helper->saveData("level", d_level);
370
371 std::stringstream medals;
372 for (int i=0;i<3;i++)
373 {
374 medals << d_medal_bonus[i] << " ";
375 }
376 retval &= helper->saveData("medals", medals.str());
377 retval &= helper->saveData("battlesnumber",d_battles_number);
378
379 std::stringstream temples;
380 for (auto it: d_visitedTemples)
381 temples << it << " ";
382 retval &= helper->saveData("visited_temples", temples.str());
383
384 return retval;
385 }
386
setInShip(bool s)387 void Army::setInShip (bool s)
388 {
389 if (s == true && isFlyer() == true)
390 s = false;
391 d_ship = s;
392 }
393
isFlyer() const394 bool Army::isFlyer() const
395 {
396 return d_move_bonus == Tile::isFlying();
397 }
398
399 //! Sets this army as being fortified (+1 to stack)
setFortified(bool f)400 void Army::setFortified (bool f)
401 {
402 if (getFortified() == true && f == false)
403 d_army_bonus ^= Army::FORTIFY;
404 else if (getFortified() == false && f == true)
405 d_army_bonus |= Army::FORTIFY;
406 }
407
408 //! get the fortify flag for this army
getFortified() const409 bool Army::getFortified () const
410 {
411 return (d_army_bonus & Army::FORTIFY) == Army::FORTIFY;
412 }
413
blessedAtTemple(guint32 temple_id) const414 bool Army::blessedAtTemple(guint32 temple_id) const
415 {
416 unsigned int id = temple_id;
417 if (std::find (d_visitedTemples.begin(), d_visitedTemples.end(), id) ==
418 d_visitedTemples.end())
419 return false;
420
421 return true;
422 }
423
getDefendsRuins() const424 bool Army::getDefendsRuins() const
425 {
426 ArmyProto *a = Armysetlist::getInstance()->getArmy(d_armyset, d_type_id);
427 if (a)
428 return a->getDefendsRuins();
429 else
430 return false;
431 }
432
getAwardable() const433 bool Army::getAwardable() const
434 {
435 ArmyProto *a = Armysetlist::getInstance()->getArmy(d_armyset, d_type_id);
436 if (a)
437 return a->getAwardable();
438 else
439 return false;
440 }
441
getName() const442 Glib::ustring Army::getName() const
443 {
444 ArmyProto *a = Armysetlist::getInstance()->getArmy(d_armyset, d_type_id);
445 if (a)
446 return a->getName();
447 else
448 return "";
449 }
450
morph(const ArmyProto * army)451 void Army::morph(const ArmyProto *army)
452 {
453 setStat(Army::STRENGTH, army->getStrength());
454 setStat(Army::MOVES, army->getMaxMoves());
455 setStat(Army::MOVE_BONUS, army->getMoveBonus());
456 setStat(Army::ARMY_BONUS, army->getArmyBonus());
457 d_type_id = army->getId();
458 d_armyset = army->getArmyset();
459 }
460