initial commit, lordsawar source, slightly modified
[lordsawar] / src / army.cpp
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 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 <algorithm>
25 #include "army.h"
26 #include "armyprodbase.h"
27 #include "armyproto.h"
28 #include "armysetlist.h"
29 #include "counter.h"
30 #include "xmlhelper.h"
31 #include "stacklist.h"
32 #include "templelist.h"
33 #include "ucompose.hpp"
34 #include "Tile.h"
35 #include "player.h"
36
37 std::string Army::d_tag = "army";
38
39 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
40 #define debug(x)
41
42 sigc::signal<void, Army*> Army::sdying;
43
44 Army::Army(const Army& a, Player* p)
45     :ArmyBase(a), UniquelyIdentified(a), Ownable(p), d_type_id(a.d_type_id), 
46     d_armyset(a.d_armyset), d_max_hp(a.d_max_hp),
47      d_max_moves_multiplier(a.d_max_moves_multiplier),
48      d_max_moves_rest_bonus(a.d_max_moves_rest_bonus),
49      d_ship(a.d_ship), d_hp(a.d_hp), d_moves(a.d_moves), d_xp(a.d_xp),
50      d_level(a.d_level), d_battles_number(a.d_battles_number), 
51      d_number_hashit(a.d_number_hashit), 
52      d_number_hasbeenhit(a.d_number_hasbeenhit), 
53      d_visitedTemples(a.d_visitedTemples)
54 {
55   for(int i = 0; i < 3; i++)
56     d_medal_bonus[i] = a.d_medal_bonus[i];
57 }
58
59 Army::Army(const ArmyProto& a, Player* p)
60     :ArmyBase(a), UniquelyIdentified(), Ownable(p), 
61     d_type_id(a.getTypeId()), d_armyset(a.getArmyset()), 
62     d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
63     d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
64     d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
65 {
66   for(int i = 0; i < 3; i++)
67     d_medal_bonus[i] = 0;
68   d_visitedTemples.clear();
69 }
70
71 Army::Army(const ArmyProto& a, guint32 id, Player *p)
72     :ArmyBase(a), UniquelyIdentified(id), Ownable(p), 
73     d_type_id(a.getTypeId()), d_armyset(a.getArmyset()), 
74     d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
75     d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
76     d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
77 {
78   for(int i = 0; i < 3; i++)
79     d_medal_bonus[i] = 0;
80   d_visitedTemples.clear();
81 }
82
83 Army::Army(const ArmyProdBase& a, guint32 id, Player *p)
84     :ArmyBase(a), UniquelyIdentified(id), Ownable(p), 
85     d_type_id(a.getTypeId()), d_armyset(a.getArmyset()), 
86     d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
87     d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
88     d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
89 {
90   for(int i = 0; i < 3; i++)
91     d_medal_bonus[i] = 0;
92   d_visitedTemples.clear();
93 }
94
95 Army* Army::createNonUniqueArmy(const ArmyProto& a, Player *player)
96 {
97   return new Army(a, (guint32) 0, player);
98 }
99
100 Army* Army::createNonUniqueArmy(const ArmyProdBase& a, Player *player)
101 {
102   return new Army(a, (guint32) 0, player);
103 }
104
105 Army::Army(const ArmyProdBase& a, Player* p)
106     :ArmyBase(a), UniquelyIdentified(), Ownable(p), 
107     d_type_id(a.getTypeId()), d_armyset(a.getArmyset()), 
108     d_max_hp(2), d_max_moves_multiplier(1), d_max_moves_rest_bonus(0),
109     d_ship(false), d_hp(2), d_moves(a.getMaxMoves()), d_xp(0), d_level(0),
110     d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
111 {
112   for(int i = 0; i < 3; i++)
113     d_medal_bonus[i] = 0;
114   d_visitedTemples.clear();
115 }
116
117 Army::Army()
118   :ArmyBase(), UniquelyIdentified(), Ownable((Player *)0),
119     d_type_id(0), d_armyset(0), d_max_hp(2), d_max_moves_multiplier(1), 
120     d_max_moves_rest_bonus(0), d_ship(false), d_hp(2), d_moves(0), d_xp(0),
121     d_level(0), d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
122 {
123   d_visitedTemples.clear();
124 }
125
126 Army::Army(XML_Helper* helper)
127   :ArmyBase(helper), UniquelyIdentified(helper), Ownable((XML_Helper*) 0),
128     d_type_id(0), d_armyset(0), d_max_hp(2), d_max_moves_multiplier(1), 
129     d_max_moves_rest_bonus(0), d_ship(false), d_hp(2), d_moves(0), d_xp(0),
130     d_level(0), d_battles_number(0), d_number_hashit(0), d_number_hasbeenhit(0)
131 {
132   //d_owner is not read in here.  it is set to the owner of the stack
133   //in stack.cpp
134   d_visitedTemples.clear();
135
136   int ival = -1;
137   //get the information which army we are
138   helper->getData(d_type_id, "type");
139   helper->getData(d_armyset, "armyset");
140
141   helper->getData(d_hp, "hp");
142   helper->getData(d_ship, "ship");
143   helper->getData(d_moves, "moves");
144   helper->getData(d_max_moves_multiplier, "max_moves_multiplier");
145   helper->getData(d_xp, "xp");
146   helper->getData(d_level, "level");
147
148   std::string medals;
149   std::stringstream smedals;
150   bool val;
151
152   helper->getData(medals, "medals");
153   smedals.str(medals);
154
155   for(int i=0;i<3;i++)
156     {
157       smedals >> val;
158       d_medal_bonus[i]=val;
159       debug("ARMY-XML-CONSTRUCTOR medalsbonus[" << i << "]=" << d_medal_bonus[i])
160     }
161
162   helper->getData(d_battles_number, "battlesnumber");    
163
164   std::string temples;
165   std::stringstream stemples;
166   helper->getData(temples, "visited_temples");
167   stemples.str(temples);
168
169   while (stemples.eof() == false)
170     {
171       ival = -1;
172       stemples >> ival;
173       if (ival != -1)
174         d_visitedTemples.push_front(ival);
175     }
176 }
177
178 Army::~Army()
179 {
180   if (d_unique)
181     sdying.emit(this);
182 }
183
184 void Army::setStat(Army::Stat stat, guint32 value)
185 {
186   switch (stat)
187     {
188     case STRENGTH:  
189       d_strength = value;
190       if (d_strength > MAX_ARMY_STRENGTH)
191         d_strength = MAX_ARMY_STRENGTH;
192       break;
193     case HP:        
194       d_max_hp = value;
195       if (d_hp > d_max_hp)
196         d_hp = value;
197       break;
198     case MOVES:     
199       d_max_moves = value;
200       if (d_moves > d_max_moves)
201         d_moves = value;
202       break;
203     case MOVES_MULTIPLIER:
204       d_max_moves_multiplier = value;
205       break;
206     case MOVE_BONUS:    d_move_bonus = value;
207                         break;
208     case ARMY_BONUS:    d_army_bonus = value;
209                         break;
210     case SIGHT:         d_sight = value;
211                         break;
212     case SHIP:          value == 0 ? d_ship = false : d_ship = true;
213                         break;
214     }
215 }
216
217 guint32 Army::getStat(Stat stat, bool modified) const
218 {
219   switch (stat)
220     {
221     case STRENGTH:
222       return d_strength;
223     case HP:
224       return d_max_hp;
225     case MOVES:
226         {
227           if (modified)
228             return (d_max_moves + d_max_moves_rest_bonus) * d_max_moves_multiplier;
229           else
230             return d_max_moves;
231         }
232     case MOVE_BONUS:
233       return d_move_bonus;
234     case ARMY_BONUS:
235       return d_army_bonus;
236     case SIGHT:
237       return d_sight;
238     case SHIP:
239       return d_ship;
240     case MOVES_MULTIPLIER:
241       return d_max_moves_multiplier;
242     }
243
244   // should never come to this
245   return 0;
246 }
247
248 void Army::resetMoves()
249 {
250   switch (d_moves)
251     {
252     case 0: d_max_moves_rest_bonus = 0; break;
253     case 1: d_max_moves_rest_bonus = 1; break;
254     case 2: d_max_moves_rest_bonus = 2; break;
255     default: d_max_moves_rest_bonus = 2; break;
256     }
257   if (d_ship)
258     d_moves = MAX_BOAT_MOVES;
259   else
260     d_moves = getStat(MOVES);
261 }
262
263 /* is this temple one we've already visited? */
264 bool Army::bless(Temple *temple)
265 {
266   bool visited = false;
267
268   if (!temple)
269     return false;
270
271   guint32 templeId = temple->getId();
272   std::list<unsigned int>::const_iterator tit = d_visitedTemples.begin();
273   std::list<unsigned int>::const_iterator tend = d_visitedTemples.end();
274   for(;tit != tend;++tit)
275     {
276       if ((*tit) == templeId)
277         {
278           visited = true;
279           break;
280         }
281     }
282
283   if (visited == false)  /* no?  increase strength */
284     {
285       d_visitedTemples.push_back(templeId);
286       setStat(STRENGTH, d_strength + 1);
287     }
288   return !visited;
289 }
290
291
292 void Army::heal(guint32 hp)
293 {
294   if (hp == 0)
295     {
296       // if no hp are specified, we assume that the healing at the end of
297       // the turn takes place. In this case the algorithm is: Heal 10%
298       // plus 1HP for each point of vitality above 5 (or one less for each
299       // point below 5), heal a minimum of 1 HP per turn
300       hp = getStat(HP)/10;
301       if (hp <= 5)
302         hp = 1;
303       else
304         hp += 5;
305     }
306
307   d_hp += hp;
308   if (d_hp > getStat(HP))
309     d_hp = getStat(HP);
310 }
311
312 bool Army::damage(guint32 damageDone)
313 {
314   if (damageDone >= d_hp)
315     d_hp = 0;
316   else
317     d_hp -= damageDone;
318   return (d_hp == 0);
319 }
320
321 void Army::decrementMoves(guint32 moves)
322 {
323   if (moves >= d_moves)
324     d_moves = 0;
325   else
326     d_moves -= moves;
327 }
328
329 void Army::gainXp(double n)
330 {
331   d_xp += n;
332 }
333
334 bool Army::save(XML_Helper* helper) const
335 {
336   bool retval = true;
337
338   retval &= helper->openTag(Army::d_tag);
339   retval &= saveData(helper);
340   retval &= helper->closeTag();
341
342   return retval;
343 }
344
345 bool Army::saveData(XML_Helper* helper) const
346 {
347   bool retval = true;
348
349   retval &= ArmyBase::saveData(helper);
350   retval &= helper->saveData("id", d_id);
351   retval &= helper->saveData("armyset", d_armyset);
352   retval &= helper->saveData("type", d_type_id);
353   retval &= helper->saveData("hp", d_hp);
354   retval &= helper->saveData("ship", d_ship);
355   retval &= helper->saveData("moves", d_moves);
356   retval &= helper->saveData("xp", d_xp);
357   retval &= helper->saveData("max_moves_multiplier", 
358                              d_max_moves_multiplier);
359   retval &= helper->saveData("level", d_level);
360
361   std::stringstream medals;
362   for (int i=0;i<3;i++)
363     {
364       medals << d_medal_bonus[i] << " ";
365     }
366   retval &= helper->saveData("medals", medals.str());
367   retval &= helper->saveData("battlesnumber",d_battles_number);    
368
369   std::stringstream temples;
370   std::list<unsigned int>::const_iterator tit = d_visitedTemples.begin();
371   std::list<unsigned int>::const_iterator tend = d_visitedTemples.end();
372   for(;tit != tend;++tit)
373     temples << (*tit) << " ";
374   retval &= helper->saveData("visited_temples", temples.str());
375
376   return retval;
377 }
378
379 void  Army::printAllDebugInfo() const
380 {
381   std::cerr << "name = " << getName() << std::endl;
382   std::cerr << "max_hp = " << d_max_hp << std::endl;
383   std::cerr << "xp_value = " << d_xp_value << std::endl;
384   std::cerr << "strength = " << d_strength << std::endl;
385   std::cerr << "max_moves = " << d_max_moves << std::endl;
386   std::cerr << "max_moves_multiplier = " 
387     << d_max_moves_multiplier << std::endl;
388   std::cerr << "max_moves_rest_bonus = " 
389     << d_max_moves_rest_bonus << std::endl;
390   std::cerr << "upkeep = " << d_upkeep << std::endl;
391   std::cerr << "move_bonus = " << d_move_bonus << std::endl;
392   std::cerr << "ship = " << d_ship << std::endl;
393   std::cerr << "army_bonus = " << d_army_bonus << std::endl;
394
395   std::cerr << "type = "    << d_type_id    << std::endl;
396   std::cerr << "level = "   << d_level   << std::endl;
397   std::cerr << "xp = "      << d_xp      << std::endl;
398
399   std::cerr << "medal[0] = " << d_medal_bonus[0] << std::endl;
400   std::cerr << "medal[1] = " << d_medal_bonus[1] << std::endl;
401   std::cerr << "medal[2] = " << d_medal_bonus[2] << std::endl;
402
403   std::cerr << "battle number = "     << d_battles_number    << std::endl;
404   std::cerr << "has hit = "           << d_number_hashit     << std::endl;
405   std::cerr << "has been hit = "      << d_number_hasbeenhit << std::endl;
406   std::stringstream temples;
407   std::list<unsigned int>::const_iterator tit = d_visitedTemples.begin();
408   std::list<unsigned int>::const_iterator tend = d_visitedTemples.end();
409   for(;tit != tend;++tit)
410     temples << (*tit) << " ";
411   std::cerr << "visited temples with ids = " << temples << std::endl;
412 }
413
414 void Army::setInShip (bool s)
415 {
416   d_ship = s;
417 }
418
419 //! Sets this army as being fortified (+1 to stack)
420 void Army::setFortified (bool f)
421 {
422   if (getFortified() == true && f == true)
423     ; // do nothing
424   else if (getFortified() == true && f == false)
425     d_army_bonus ^= Army::FORTIFY;
426   else if (getFortified() == false && f == true)
427     d_army_bonus |= Army::FORTIFY;
428   else if (getFortified() == false && f == false)
429     ; // do nothing
430 }
431
432 //! get the fortify flag for this army
433 bool Army::getFortified () const
434 {
435   return (d_army_bonus & Army::FORTIFY) == Army::FORTIFY;
436 }
437
438 bool Army::blessedAtTemple(guint32 temple_id) const
439 {
440   unsigned int id = temple_id;
441   if (std::find (d_visitedTemples.begin(), d_visitedTemples.end(), id) ==
442       d_visitedTemples.end())
443     return false;
444
445   return true;
446 }
447
448 bool Army::getDefendsRuins() const
449 {
450   ArmyProto *a = Armysetlist::getInstance()->getArmy(d_armyset, d_type_id);
451   if (a)
452     return a->getDefendsRuins();
453   else
454     return false;
455 }
456
457 bool Army::getAwardable() const
458 {
459   ArmyProto *a = Armysetlist::getInstance()->getArmy(d_armyset, d_type_id);
460   if (a)
461     return a->getAwardable();
462   else
463     return false;
464 }
465
466 std::string Army::getName() const
467 {
468   ArmyProto *a = Armysetlist::getInstance()->getArmy(d_armyset, d_type_id);
469   if (a)
470     return a->getName();
471   else
472     return "";
473 }
474
475 void Army::morph(const ArmyProto *army)
476 {
477   setStat(Army::STRENGTH, army->getStrength());
478   setStat(Army::MOVES, army->getMaxMoves());
479   setStat(Army::MOVE_BONUS, army->getMoveBonus());
480   setStat(Army::ARMY_BONUS, army->getArmyBonus());
481   d_type_id = army->getTypeId();
482   d_armyset = army->getArmyset();
483 }