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