1 // Copyright (C) 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2006 Andrea Paternesi
4 // Copyright (C) 2004 Bryan Duff
5 // Copyright (C) 2006, 2007, 2008, 2011, 2014, 2015 Ben Asselstine
6 // Copyright (C) 2008 Ole Laursen
7 //
8 //  This program is free software; you can redistribute it and/or modify
9 //  it under the terms of the GNU General Public License as published by
10 //  the Free Software Foundation; either version 3 of the License, or
11 //  (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU Library General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //  02110-1301, USA.
22 
23 #include "fight.h"
24 #include <assert.h>
25 #include <math.h>       // for has_hit()
26 #include "army.h"
27 #include "hero.h"
28 #include "stacklist.h"
29 #include "player.h"
30 #include "playerlist.h"
31 #include "Item.h"
32 #include "GameMap.h"
33 #include "citylist.h"
34 #include "city.h"
35 #include "stack.h"
36 #include "Backpack.h"
37 #include "stacktile.h"
38 #include "rnd.h"
39 
40 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
41 #define debug(x)
42 
Fighter(const Fighter & f)43 Fighter::Fighter(const Fighter &f)
44  : army(f.army), pos(f.pos), terrain_strength(f.terrain_strength)
45 {
46 }
47 
Fighter(Army * a,Vector<int> p)48 Fighter::Fighter(Army* a, Vector<int> p)
49     :army(a), pos(p)
50 {
51 }
52 
53 //take a list of stacks and create an ordered list of armies
orderArmies(std::list<Stack * > stacks,std::vector<Army * > & armies)54 void Fight::orderArmies(std::list<Stack*> stacks, std::vector<Army*> &armies)
55 {
56   std::list<Stack*>::iterator it;
57   if (stacks.empty())
58     return;
59   for (it = stacks.begin(); it != stacks.end(); it++)
60     for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
61       armies.push_back((*sit));
62 
63   //okay now sort the army list according to the player's fight order
64   std::sort(armies.begin(), armies.end(), Stack::armyCompareFightOrder);
65 
66   return;
67 }
68 
Fight(Stack * attacker,Stack * defender,FightType type)69 Fight::Fight(Stack* attacker, Stack* defender, FightType type)
70     : d_turn(0), d_result(DRAW), d_type(type)
71 {
72   std::list<Stack *> attackers;
73   std::list<Stack *> defenders;
74 
75   debug("Fight between " <<attacker->getId() <<" and " <<defender->getId());
76 
77   // Duel case: two stacks fight each other; Nothing further to be done
78   // Important: We always assume that the attacking/defending stacks are
79   // the first in the list!!!
80   attackers.push_back(attacker);
81   defenders.push_back(defender);
82 
83   // What we do here: In the setup, we need to find out all armies that
84   // participate in the fight.  If a city is being attacked then the
85   // defender gets any other stacks in the cities.
86   //
87 
88   Maptile *mtile = GameMap::getInstance()->getTile(defender->getPos());
89   City *city = GameMap::getCity(defender->getPos());
90   //Vector<int> p = defender->getPos();
91 
92   if (city && city->isBurnt() == false &&
93       city->getOwner() == defender->getOwner())
94     {
95       /* we check the owner here because:
96        * StackInfoDialog does a fight for kicks with a neutral scout,
97        * on the tile of the selected stack, which could be in a city.
98        */
99       std::vector<Stack*> stacks = city->getDefenders();
100       for (std::vector<Stack*>::iterator it = stacks.begin();
101            it != stacks.end(); it++)
102         {
103           Stack *s = *it;
104           if (s == defenders.front())
105             continue;
106           defenders.push_back(s);
107         }
108     }
109   else if ((!city || city->isBurnt() == true) &&
110            defender->getOwner() != Playerlist::getInstance()->getNeutral())
111     {
112       Vector<int> pos = defender->getPos();
113       std::vector<Stack*> stacks =
114         GameMap::getStacks(pos)->getEnemyStacks(attacker->getOwner());
115       for (std::vector<Stack*>::iterator it = stacks.begin();
116            it != stacks.end(); it++)
117         {
118           Stack *s = *it;
119           if (s == defenders.front())
120             continue;
121           defenders.push_back(s);
122         }
123     }
124 
125   setupFight (attackers, defenders, city != NULL, mtile->getType(), type);
126 }
127 
Fight(std::list<Stack * > attackers,std::list<Stack * > defenders,std::list<FightItem> history)128 Fight::Fight(std::list<Stack*> attackers, std::list<Stack*> defenders,
129              std::list<FightItem> history)
130 {
131   d_attackers = attackers;
132   d_defenders = defenders;
133   d_actions = history;
134 
135   fillInInitialHPs();
136 }
137 
setupFight(std::list<Stack * > attackers,std::list<Stack * > defenders,bool city,Tile::Type terrain,FightType type)138 void Fight::setupFight(std::list<Stack*> attackers, std::list<Stack*> defenders, bool city, Tile::Type terrain, FightType type)
139 {
140   d_type = type;
141   d_attackers = attackers;
142   d_defenders = defenders;
143   std::vector<Army*> def;
144   orderArmies (d_defenders, def);
145   for (auto a : def)
146     d_def_close.push_back(new Fighter(a, defenders.front()->getPos()));
147   std::vector<Army*> att;
148   orderArmies (d_attackers, att);
149   for (auto a : att)
150     d_att_close.push_back(new Fighter(a, attackers.front()->getPos()));
151   fillInInitialHPs();
152   for (auto f : d_att_close)
153     d_initial_att_close.push_back(new Fighter(*f));
154   for (auto f : d_def_close)
155     d_initial_def_close.push_back(new Fighter(*f));
156   Maptile *mtile = new Maptile(-1, -1, terrain);
157   if (city)
158     mtile->setBuilding(Maptile::CITY);
159   calculateBonus(mtile);
160   delete mtile;
161 }
162 
Fight(std::list<Stack * > attackers,std::list<Stack * > defenders,bool city,Tile::Type terrain,FightType type)163 Fight::Fight(std::list<Stack*> attackers, std::list<Stack*> defenders, bool city, Tile::Type terrain, FightType type)
164 {
165   setupFight (attackers, defenders, city, terrain, type);
166 }
167 
~Fight()168 Fight::~Fight()
169 {
170   d_attackers.clear();
171   d_defenders.clear();
172 
173   // clear all fighter items in all lists
174   while (!d_att_close.empty())
175     {
176       delete (*d_att_close.begin());
177       d_att_close.erase(d_att_close.begin());
178     }
179 
180   while (!d_def_close.empty())
181     {
182       delete (*d_def_close.begin());
183       d_def_close.erase(d_def_close.begin());
184     }
185 
186   while (!d_initial_att_close.empty())
187     {
188       delete (*d_initial_att_close.begin());
189       d_initial_att_close.erase(d_initial_att_close.begin());
190     }
191 
192   while (!d_initial_def_close.empty())
193     {
194       delete (*d_initial_def_close.begin());
195       d_initial_def_close.erase(d_initial_def_close.begin());
196     }
197 }
198 
battle(bool intense)199 void Fight::battle(bool intense)
200 {
201   d_intense_combat = intense;
202 
203   // first, fight until the fight is over
204   for (d_turn = 0; doRound(); d_turn++);
205 
206   // Now we have to set the fight result.
207 
208   // First, look if the attacker died; the attacking stack is the first
209   // one in the list
210   bool survivor = false;
211   Stack* s = d_attackers.front();
212   for (Stack::const_iterator it = s->begin(); it != s->end(); it++)
213     if ((*it)->getHP() > 0)
214       {
215 	survivor = true;
216 	break;
217       }
218 
219   if (!survivor)
220       d_result = DEFENDER_WON;
221   else
222     {
223       // Now look if the defender died; also the first in the list
224       survivor = false;
225       s = d_defenders.front();
226       for (Stack::const_iterator it = s->begin(); it != s->end(); it++)
227 	if ((*it)->getHP() > 0)
228 	  {
229 	    survivor = true;
230 	    break;
231 	  }
232 
233       if (!survivor)
234 	d_result = ATTACKER_WON;
235     }
236 
237   if (d_type == FOR_KICKS)
238     {
239       //revert the hitpoints to what they started out as.
240       //if they were already hurt prior to the battle, they go back to
241       //being already hurt.
242       std::list<Stack*>::iterator it;
243       for (it = d_attackers.begin(); it != d_attackers.end(); it++)
244 	for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
245           (*sit)->setHP(initial_hps[(*it)->getId()]);
246 
247       for (it = d_defenders.begin(); it != d_defenders.end(); it++)
248 	for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
249           (*sit)->setHP(initial_hps[(*it)->getId()]);
250     }
251 }
252 
findArmyById(const std::list<Stack * > & l,guint32 id)253 Army *Fight::findArmyById(const std::list<Stack *> &l, guint32 id)
254 {
255   for (std::list<Stack *>::const_iterator i = l.begin(), end = l.end();
256        i != end; ++i) {
257     Army *a = (*i)->getArmyById(id);
258     if (a)
259       return a;
260   }
261 
262   return 0;
263 }
264 
battleFromHistory()265 Fight::Result Fight::battleFromHistory()
266 {
267   for (std::list<FightItem>::iterator i = d_actions.begin(),
268          end = d_actions.end(); i != end; ++i) {
269     FightItem &f = *i;
270 
271     Army *a = findArmyById(d_attackers, f.id);
272     if (!a)
273       a = findArmyById(d_defenders, f.id);
274 
275     a->damage(f.damage);
276   }
277   //is there anybody alive in the attackers?
278   for (std::list<Stack*>::iterator it = d_attackers.begin(); it != d_attackers.end(); it++)
279     {
280       for (Stack::iterator i = (*it)->begin(); i != (*it)->end(); i++)
281 	{
282 	  if ((*i)->getHP() > 0)
283 	    return Fight::ATTACKER_WON;
284 	}
285     }
286 
287   return Fight::DEFENDER_WON;
288 }
289 
doRound()290 bool Fight::doRound()
291 {
292   if (MAX_ROUNDS && d_turn >= MAX_ROUNDS)
293     return false;
294 
295   debug ("Fight round #" <<d_turn);
296 
297   //fight the first one in attackers with the first one in defenders
298   std::list<Fighter*>::iterator ffit = d_att_close.begin();
299   std::list<Fighter*>::iterator efit = d_def_close.begin();
300 
301   //have the attacker and defender try to hit each other
302   fightArmies(*ffit, *efit);
303 
304   if (*efit && (*efit)->army->getHP() <= 0)
305     remove((*efit));
306 
307   if (*ffit && (*ffit)->army->getHP() <= 0)
308     remove((*ffit));
309 
310   if (d_def_close.empty() || d_att_close.empty())
311     return false;
312 
313   return true;
314 }
315 
calculateBaseStrength(std::list<Fighter * > fighters)316 void Fight::calculateBaseStrength(std::list<Fighter*> fighters)
317 {
318   std::list<Fighter*>::iterator fit;
319   for (fit = fighters.begin(); fit != fighters.end(); fit++)
320     {
321       if ((*fit)->army->getStat(Army::SHIP))
322 	(*fit)->terrain_strength = (*fit)->army->getStat(Army::BOAT_STRENGTH);
323       else
324 	(*fit)->terrain_strength = (*fit)->army->getStat(Army::STRENGTH);
325     }
326 }
327 
calculateTerrainModifiers(std::list<Fighter * > fighters,Maptile * mtile,bool defender)328 void Fight::calculateTerrainModifiers(std::list<Fighter*> fighters, Maptile *mtile, bool defender)
329 {
330   guint32 army_bonus;
331   std::list<Fighter*>::iterator fit;
332   for (fit = fighters.begin(); fit != fighters.end(); fit++)
333     {
334       if ((*fit)->army->getStat(Army::SHIP))
335 	continue;
336 
337       bool tower = false;
338       if (defender)
339         tower = (*fit)->army->getFortified();
340       mtile = GameMap::getInstance()->getTile((*fit)->pos);
341       army_bonus = (*fit)->army->getStat(Army::ARMY_BONUS);
342 
343       if (army_bonus & Army::ADD1STRINOPEN && mtile->isOpenTerrain() == Tile::GRASS && !tower)
344 	(*fit)->terrain_strength += 1;
345 
346       if (army_bonus & Army::ADD1STRINFOREST &&
347 	  mtile->getType() == Tile::FOREST && !mtile->isCityTerrain() && !tower)
348 	(*fit)->terrain_strength += 1;
349 
350       if (army_bonus & Army::ADD2STRINFOREST &&
351 	  mtile->getType() == Tile::FOREST && !mtile->isCityTerrain() && !tower)
352 	(*fit)->terrain_strength += 2;
353 
354       if (army_bonus & Army::ADD1STRINHILLS && mtile->isHillyTerrain() &&
355           !tower)
356 	(*fit)->terrain_strength += 1;
357 
358       if (army_bonus & Army::ADD2STRINHILLS && mtile->isHillyTerrain() &&
359           !tower)
360 	(*fit)->terrain_strength += 2;
361 
362       if (army_bonus & Army::ADD1STRINCITY && (mtile->isCityTerrain() || tower))
363 	(*fit)->terrain_strength += 1;
364 
365       if (army_bonus & Army::ADD2STRINCITY && (mtile->isCityTerrain() || tower))
366 	(*fit)->terrain_strength += 2;
367 
368       if (army_bonus & Army::ADD2STRINOPEN && mtile->isOpenTerrain() && !tower)
369 	(*fit)->terrain_strength += 2;
370 
371       if ((*fit)->terrain_strength > 9) //terrain strength can't ever exceed 9
372 	(*fit)->terrain_strength = 9;
373 
374     }
375 }
376 
calculateModifiedStrengths(std::list<Fighter * > friendly,std::list<Fighter * > enemy,bool friendlyIsDefending,Hero * strongestHero,Maptile * mtile)377 void Fight::calculateModifiedStrengths (std::list<Fighter*>friendly,
378 					std::list<Fighter*>enemy,
379 					bool friendlyIsDefending,
380 					Hero *strongestHero,
381                                         Maptile *mtile)
382 {
383   guint32 army_bonus;
384   std::list<Fighter*>::iterator fit;
385 
386   //find highest non-hero bonus
387   guint32 highest_non_hero_bonus = 0;
388   for (fit = friendly.begin(); fit != friendly.end(); fit++)
389     {
390       guint32 non_hero_bonus = 0;
391       if ((*fit)->army->isHero())
392 	continue;
393       if ((*fit)->army->getStat(Army::SHIP))
394         continue;
395       army_bonus = (*fit)->army->getStat(Army::ARMY_BONUS);
396 
397       if (army_bonus & Army::ADD1STACKINHILLS && mtile->isHillyTerrain())
398 	non_hero_bonus += 1;
399 
400       if (army_bonus & Army::ADD1STACK)
401 	non_hero_bonus += 1;
402 
403       if (army_bonus & Army::ADD2STACK)
404 	non_hero_bonus += 2;
405 
406       if (non_hero_bonus > highest_non_hero_bonus)
407 	highest_non_hero_bonus = non_hero_bonus;
408     }
409 
410   // does the defender cancel our non hero bonus?
411   for (fit = enemy.begin(); fit != enemy.end(); fit++)
412     {
413       army_bonus = (*fit)->army->getStat(Army::ARMY_BONUS);
414       if (army_bonus & Army::SUBALLNONHEROBONUS)
415 	{
416 	  highest_non_hero_bonus = 0; //yes
417 	  break;
418 	}
419     }
420 
421   //find hero bonus of strongest hero
422   guint32 hero_bonus = 0;
423   if (strongestHero)
424     {
425       // first get command items from ALL heroes in the stack
426       for (fit = friendly.begin(); fit != friendly.end(); fit++)
427 	{
428 	  if ((*fit)->army->isHero())
429 	    {
430 	      Hero *h = dynamic_cast<Hero*>((*fit)->army);
431 	      hero_bonus = h->getBackpack()->countStackStrengthBonuses();
432 	    }
433 	}
434     }
435 
436   //now add on the hero's natural command
437   if (strongestHero)
438     {
439       hero_bonus += strongestHero->calculateNaturalCommand();
440     }
441 
442   // does the defender cancel our hero bonus?
443   for (fit = enemy.begin(); fit != enemy.end(); fit++)
444     {
445       army_bonus = (*fit)->army->getStat(Army::ARMY_BONUS);
446       if (army_bonus & Army::SUBALLHEROBONUS)
447 	{
448 	  hero_bonus = 0; //yep
449 	  break;
450 	}
451     }
452 
453   guint32 fortify_bonus = 0;
454   guint32 city_bonus = 0;
455   if (friendlyIsDefending)
456     {
457       // calculate the city bonus
458       fit = friendly.begin();
459       mtile = GameMap::getInstance()->getTile((*fit)->pos);
460       City *c = Citylist::getInstance()->getNearestCity((*fit)->pos);
461       if (c && mtile->getBuilding() == Maptile::CITY)
462         {
463           if (c->isBurnt())
464             city_bonus = 0;
465           else
466             city_bonus = c->getDefenseLevel() - 1;
467         }
468       else
469         {
470           if (mtile->getBuilding() == Maptile::TEMPLE)
471             city_bonus = 2;
472           else if (mtile->getBuilding() == Maptile::RUIN)
473             city_bonus = 2;
474           else if (mtile->isCityTerrain() == false)
475             {
476               for (fit = friendly.begin(); fit != friendly.end(); fit++)
477                 {
478                   army_bonus = (*fit)->army->getStat(Army::ARMY_BONUS);
479                   if (army_bonus & Army::FORTIFY)
480                     {
481                       fortify_bonus = 1;
482                       break;
483                     }
484                 }
485             }
486         }
487 
488       // does the attacker cancel our city bonus?
489       for (fit = enemy.begin(); fit != enemy.end(); fit++)
490         {
491           if ((*fit)->army->getStat(Army::SHIP))
492             continue;
493           army_bonus = (*fit)->army->getStat(Army::ARMY_BONUS);
494           if (army_bonus & Army::SUBALLCITYBONUS)
495             {
496               city_bonus = 0; //yep
497               fortify_bonus = 0;
498               break;
499             }
500         }
501     }
502 
503   guint32 total_bonus = highest_non_hero_bonus + hero_bonus + fortify_bonus +
504     city_bonus;
505 
506   if (total_bonus > 5) //total bonus can't exceed 5
507     total_bonus = 5;
508 
509   //add it to the terrain strength of each unit
510   for (fit = friendly.begin(); fit != friendly.end(); fit++)
511     {
512       if ((*fit)->army->getStat(Army::SHIP))
513         continue;
514       (*fit)->terrain_strength += total_bonus;
515     }
516 }
517 
calculateFinalStrengths(std::list<Fighter * > friendly,std::list<Fighter * > enemy)518 void Fight::calculateFinalStrengths (std::list<Fighter*> friendly, std::list<Fighter*> enemy)
519 {
520   guint32 army_bonus;
521   std::list<Fighter*>::iterator efit;
522   std::list<Fighter*>::iterator ffit;
523   for (efit = enemy.begin(); efit != enemy.end(); efit++)
524     {
525       army_bonus = (*efit)->army->getStat(Army::ARMY_BONUS);
526       if (army_bonus & Army::SUB1ENEMYSTACK ||
527           army_bonus & Army::SUB2ENEMYSTACK)
528 	{
529           int dec = 0;
530           if (army_bonus & Army::SUB1ENEMYSTACK)
531             dec += 1;
532           if (army_bonus & Army::SUB2ENEMYSTACK)
533             dec += 2;
534 	  for (ffit = friendly.begin(); ffit != friendly.end(); ffit++)
535             {
536               if ((*ffit)->army->getStat(Army::SHIP))
537                 continue;
538               (*ffit)->terrain_strength -= dec;
539               if ((*ffit)->terrain_strength <= 0)
540                 (*ffit)->terrain_strength = 1;
541             }
542 	  break;
543 	}
544     }
545 }
546 
calculateBonus(Maptile * mtile)547 void Fight::calculateBonus(Maptile *mtile)
548 {
549   // If there is a hero, add a +1 strength bonus
550   std::list<Stack*>::const_iterator it;
551   Stack::const_iterator sit;
552   std::list<Fighter*>::iterator fit;
553 
554   // go get the base strengths of all attackers
555   // this includes items with battle bonuses for the hero
556   // naval units always have strength = 4
557   calculateBaseStrength (d_att_close);
558   calculateBaseStrength (d_def_close);
559 
560   // now determine the terrain strength by adding the terrain modifiers
561   // to the base strength
562   // naval units always have a strength of 4
563   calculateTerrainModifiers (d_att_close, mtile, false);
564   calculateTerrainModifiers (d_def_close, mtile, true);
565 
566   //calculate hero, non-hero, city, and fortify bonuses
567   it = d_attackers.begin();
568   Army *a = (*it)->getStrongestHero();
569   Hero *h = dynamic_cast<Hero*>(a);
570   calculateModifiedStrengths (d_att_close, d_def_close, false, h, mtile);
571   Hero *strongestHero = 0;
572   guint32 highest_strength = 0;
573   for (it = d_defenders.begin(); it != d_defenders.end(); it++)
574     {
575       a = (*it)->getStrongestHero();
576       if (!a)
577 	continue;
578       h = dynamic_cast<Hero*>(a);
579       if (h->getStat(Army::STRENGTH) > highest_strength)
580 	{
581 	  highest_strength = h->getStat(Army::STRENGTH);
582 	  strongestHero = h;
583 	}
584     }
585   calculateModifiedStrengths (d_def_close, d_att_close, true, strongestHero,
586                               mtile);
587 
588   calculateFinalStrengths (d_att_close, d_def_close);
589   calculateFinalStrengths (d_def_close, d_att_close);
590 
591 }
592 
fightArmies(Fighter * attacker,Fighter * defender)593 void Fight::fightArmies(Fighter* attacker, Fighter* defender)
594 {
595   guint32 sides = 0;
596 
597   if (!attacker || !defender)
598     return;
599 
600   Army *a = attacker->army;
601   Army *d = defender->army;
602 
603   debug("Army " << a->getId() << " attacks " << d->getId());
604 
605   if (d_intense_combat == true)
606     sides = BATTLE_DICE_SIDES_INTENSE;
607   else
608     sides = BATTLE_DICE_SIDES_NORMAL;
609 
610   // factor used for some calculation regarding gaining medals
611   double xp_factor = a->getXpReward() / d->getXpReward();
612 
613   // the clash has to be documented for later use in the fight dialog
614 
615   // make a swing at the opponent
616   // take one hit point off, per hit.
617 
618   FightItem item;
619   item.turn = d_turn;
620   int damage = 0;
621   item.id = d->getId();
622 
623   while (damage == 0)
624     {
625       int attacker_roll = Rnd::rand() % sides;
626       int defender_roll = Rnd::rand() % sides;
627 
628       if (attacker_roll < attacker->terrain_strength &&
629 	  defender_roll >= defender->terrain_strength)
630 	{
631 	  //hit defender
632 	  if (d_type == FOR_KEEPS)
633 	    {
634 	      a->setNumberHasHit(a->getNumberHasHit() + (1/xp_factor));
635 	      d->setNumberHasBeenHit(d->getNumberHasBeenHit() + (1/xp_factor));
636 	    }
637 	  d->damage(1);
638 	  damage = 1;
639 	  item.id = d->getId();
640 	}
641       else if (defender_roll < defender->terrain_strength &&
642 	       attacker_roll >= attacker->terrain_strength)
643 	{
644 	  //hit attacker
645 	  if (d_type == FOR_KEEPS)
646 	    {
647 	      d->setNumberHasHit(d->getNumberHasHit() + (1/xp_factor));
648 	      a->setNumberHasBeenHit(a->getNumberHasBeenHit() + (1/xp_factor));
649 	    }
650 	  a->damage(1);
651 	  damage = 1;
652 	  item.id = a->getId();
653 	}
654       else
655         continue;
656     }
657   // continue documenting the engagement
658 
659   item.damage = damage;
660   d_actions.push_back(item);
661 }
662 
remove(Fighter * f)663 void Fight::remove(Fighter* f)
664 {
665   std::list<Fighter*>::iterator it;
666 
667   // is the fighter in the attacker lists?
668   for (it = d_att_close.begin(); it != d_att_close.end(); it++)
669     if ((*it) == f)
670       {
671 	d_att_close.erase(it);
672 	delete f;
673 	return;
674       }
675 
676   // or in the defender lists?
677   for (it = d_def_close.begin(); it != d_def_close.end(); it++)
678     if ((*it) == f)
679       {
680 	d_def_close.erase(it);
681 	delete f;
682 	return;
683       }
684 
685   // if the fighter wa sin no list, we are rather careful and don't do anything
686   debug("Fight: fighter without list!")
687 }
688 
getModifiedStrengthBonus(Army * a)689 guint32 Fight::getModifiedStrengthBonus(Army *a)
690 {
691   std::list<Fighter*>::iterator it;
692   for (it = d_att_close.begin(); it != d_att_close.end(); it++)
693     if ((*it)->army == a)
694       return (*it)->terrain_strength;
695   for (it = d_def_close.begin(); it != d_def_close.end(); it++)
696     if ((*it)->army == a)
697       return (*it)->terrain_strength;
698   return 0;
699 }
700 
setModifiedStrengthBonus(Army * a,guint32 str)701 void Fight::setModifiedStrengthBonus(Army *a, guint32 str)
702 {
703   std::list<Fighter*>::iterator it;
704   for (it = d_att_close.begin(); it != d_att_close.end(); it++)
705     if ((*it)->army == a)
706       {
707         (*it)->terrain_strength = str;
708         return;
709       }
710   for (it = d_def_close.begin(); it != d_def_close.end(); it++)
711     if ((*it)->army == a)
712       {
713         (*it)->terrain_strength = str;
714         return;
715       }
716 }
717 
fillInInitialHPs()718 void Fight::fillInInitialHPs()
719 {
720   for (std::list<Stack *>::iterator i = d_attackers.begin();
721        i != d_attackers.end(); ++i)
722     for (Stack::iterator j = (*i)->begin(); j != (*i)->end(); ++j)
723       initial_hps[(*j)->getId()] = (*j)->getHP();
724 
725   for (std::list<Stack *>::iterator i = d_defenders.begin();
726        i != d_defenders.end(); ++i)
727     for (Stack::iterator j = (*i)->begin(); j != (*i)->end(); ++j)
728       initial_hps[(*j)->getId()] = (*j)->getHP();
729 }
730 
calculateFightBox(Fight & fight)731 LocationBox Fight::calculateFightBox(Fight &fight)
732 {
733   /*
734    this is all about figuring out where the explosion
735    is supposed to appear on the big map.
736    the desired behaviour is:
737    when we attack a city the explosion covers where we are
738    attacking from, to where we are attacking to.
739    it's tricky though because we step into the city, so we
740    have to look at our track to see where we were.
741    when attacking in the field, the explosion covers the
742    enemy stack.
743    maybe defenders can be empty?
744    */
745   Vector<int> dest = fight.getAttackers().front()->getPos();
746   if (Citylist::getInstance()->getObjectAt(dest) == NULL)
747     {
748       if (!fight.getDefenders().empty())
749         return LocationBox(fight.getDefenders().front()->getPos());
750       else
751         return LocationBox(dest);
752     }
753   Player *p = fight.getAttackers().front()->getOwner();
754   Stack *s = fight.getAttackers().front();
755   std::list<Vector<int> > tracks = p->getStackTrack(s);
756   if (tracks.size() >= 2)
757     {
758       std::list<Vector<int> >::iterator it = tracks.end();
759       it--; it--;
760       return LocationBox (*it, dest);
761     }
762   else
763     {
764       //this shouldn't be the case
765       return LocationBox(s->getPos(), dest);
766     }
767 }
768