initial commit, lordsawar source, slightly modified
[lordsawar] / src / stack.cpp
1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2000, Anluan O'Brien
3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
4 // Copyright (C) 2004 John Farrell
5 // Copyright (C) 2004, 2005 Andrea Paternesi
6 // Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
7 // Copyright (C) 2007, 2008 Ole Laursen
8 //
9 //  This program is free software; you can redistribute it and/or modify
10 //  it under the terms of the GNU General Public License as published by
11 //  the Free Software Foundation; either version 3 of the License, or
12 //  (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU Library General Public License for more details.
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
22 //  02110-1301, USA.
23
24 #include <sigc++/functors/mem_fun.h>
25 #include <assert.h>
26 #include <algorithm>
27
28 #include "stack.h"
29 #include "playerlist.h"
30 #include "path.h"
31 #include "armysetlist.h"
32 #include "counter.h"
33 #include "army.h"
34 #include "hero.h"
35 #include "GameMap.h"
36 #include "vector.h"
37 #include "xmlhelper.h"
38 #include "FogMap.h"
39 #include "player.h"
40 #include "Backpack.h"
41 #include "AI_Analysis.h"
42
43 std::string Stack::d_tag = "stack";
44 using namespace std;
45
46 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
47 #define debug(x)
48
49 Stack::Stack(Player* player, Vector<int> pos)
50     : UniquelyIdentified(), Movable(pos), Ownable(player), d_defending(false), 
51     d_parked(false), d_deleting(false)
52 {
53     d_path = new Path();
54 }
55
56 Stack::Stack(guint32 id, Player* player, Vector<int> pos)
57     : UniquelyIdentified(id), Movable(pos), Ownable(player), 
58     d_defending(false), d_parked(false), d_deleting(false)
59 {
60     d_path = new Path();
61 }
62
63 Stack::Stack(const Stack& s)
64     : UniquelyIdentified(s), Movable(s), Ownable(s), 
65     d_defending(s.d_defending), d_parked(s.d_parked), 
66     d_deleting(false)
67 {
68   if (s.d_path == NULL)
69     {
70       printf("Stack %d has a null path!\n", d_id);
71     }
72     d_path = new Path(*s.d_path);
73
74     for (const_iterator sit = s.begin(); sit != s.end(); sit++)
75     {
76         if ((*sit)->isHero())
77           {
78             Army *h = new Hero(dynamic_cast<Hero&>(**sit));
79             push_back(h);
80           }
81         else
82           {
83             Army *a = new Army((**sit), (*sit)->getOwner());
84             push_back(a);
85           }
86     }
87 }
88
89 Stack::Stack(XML_Helper* helper)
90   : UniquelyIdentified(helper), Movable(helper), Ownable(helper), 
91     d_deleting(false)
92 {
93   helper->getData(d_defending, "defending");
94   helper->getData(d_parked, "parked");
95
96   helper->registerTag(Path::d_tag, sigc::mem_fun((*this), &Stack::load));
97   helper->registerTag(Army::d_tag, sigc::mem_fun((*this), &Stack::load));
98   helper->registerTag(Hero::d_tag, sigc::mem_fun((*this), &Stack::load));
99 }
100
101 Stack::~Stack()
102 {
103   d_deleting = true;
104   if (d_unique)
105     sdying.emit(this);
106
107   delete d_path;
108   flClear();
109 }
110
111 void Stack::setPlayer(Player* p)
112 {
113   // we need to change the armies' loyalties as well!!
114   setOwner(p);
115   for (iterator it = begin(); it != end(); it++)
116     (*it)->setOwner(p);
117 }
118
119 void Stack::moveOneStep(bool skipping)
120 {
121   debug("moveOneStep()");
122
123   Vector<int> dest = getFirstPointInPath();
124   moveToDest(dest, skipping);
125
126   //now remove first point of the path
127   d_path->eraseFirstPoint();
128 }
129
130 bool Stack::isMovingToOrFromAShip(Vector<int> dest, bool &on_ship) const
131 {
132   Vector<int> pos = getPos();
133
134   bool to_city = GameMap::getInstance()->getBuilding(dest) == Maptile::CITY;
135   bool on_city = GameMap::getInstance()->getBuilding(pos) == Maptile::CITY;
136
137   bool on_port = GameMap::getInstance()->getBuilding(pos) == Maptile::PORT;
138   bool on_bridge = GameMap::getInstance()->getBuilding(pos) == Maptile::BRIDGE;
139   bool to_bridge = GameMap::getInstance()->getBuilding(dest) == Maptile::BRIDGE;
140   bool on_water = (GameMap::getInstance()->getTerrainType(pos) == Tile::WATER);
141   bool to_water = (GameMap::getInstance()->getTerrainType(dest) == Tile::WATER);
142   //here we mark the armies as being on or off a boat
143   /* skipping refers to when we have to move over another friendly stack
144    * of a size that's too big to join with. */
145   if ((on_water && to_city && !on_bridge) || 
146       (on_water && on_port && !to_water && on_ship) ||
147       ((on_city || on_port) && to_water && !to_bridge) ||
148       (on_bridge && to_water && !to_bridge) ||
149       (on_bridge && !to_water && on_ship) ||
150       (on_water && to_water && !on_bridge && !on_port && !to_bridge &&
151        on_ship == false) ||
152       (!on_water && !to_water && on_ship == true))
153     {
154       on_ship = !on_ship;
155       return true;
156     }
157   return false;
158 }
159
160 void Stack::moveToDest(Vector<int> dest, bool skipping)
161 {
162   bool ship_load_unload = false;
163   if (!isFlying())
164     {
165       bool on_ship = hasShip();
166       if (isMovingToOrFromAShip(dest, on_ship) == true)
167         {
168           if (!skipping)
169             {
170               ship_load_unload = true;
171               Vector<int> pos = getPos();
172               GameMap *gm = GameMap::getInstance();
173               bool to_water = (gm->getTile(dest.x,dest.y)->getMaptileType() 
174                                == Tile::WATER);
175               for (Stack::iterator it = begin(); it != end(); it++)
176                 {
177                   if (to_water && 
178                       ((*it)->getStat(Army::MOVE_BONUS) & Tile::WATER) == 0)
179                     (*it)->setInShip(true);
180                   else
181                     (*it)->setInShip(false);
182                 }
183             }
184         }
185     }
186   else
187     {
188       for (Stack::iterator it = begin(); it != end(); it++)
189         (*it)->setInShip(false);
190     }
191
192   guint32 maptype = GameMap::getInstance()->getTile(dest.x,dest.y)->getMaptileType();
193   //how many moves does the stack need to travel to dest?
194   int needed_moves = calculateTileMovementCost(dest);
195
196   for (Stack::iterator it = begin(); it != end(); it++)
197     {
198       if (ship_load_unload)
199         (*it)->decrementMoves((*it)->getMoves());
200       else 
201         {
202           //maybe the army has a natural movement ability
203           if ((*it)->getStat(Army::MOVE_BONUS) & maptype && needed_moves > 1)
204             (*it)->decrementMoves(2);
205           else
206             (*it)->decrementMoves(needed_moves);
207         }
208     }
209
210   //update position and status
211   smoving.emit(this);
212   setPos(dest);
213   smoved.emit(this);
214
215   setFortified(false);
216   setDefending(false);
217   setParked(false);
218
219   //update fogmap
220   deFog();
221 }
222
223 void Stack::deFog()
224 {
225   getOwner()->getFogMap()->alterFogRadius(getPos(), getMaxSight(), 
226                                           FogMap::OPEN);
227   return;
228 }
229
230 // return the maximum moves of this stack by checking the moves of each army
231 guint32 Stack::getMoves() const
232 {
233   if (empty())
234     return 0;
235
236   assert(!empty());
237
238   int min = -1;
239
240   for (const_iterator it = begin(); it != end(); ++it)
241     {
242       if (min == -1)
243         min = int((*it)->getMoves());
244       else
245         min = std::min(min, int((*it)->getMoves()));
246     }
247
248   if (min <= -1)
249     return 0;
250   return min;
251 }
252
253 int Stack::getMinTileMoves() const
254 {
255   GameMap *map = GameMap::getInstance();
256   Rectangle bounds = map->get_boundary();
257
258   std::vector<Vector<int> > tiles;
259   tiles.push_back(Vector<int>(getPos().x + 1, getPos().y - 1));
260   tiles.push_back(Vector<int>(getPos().x,     getPos().y - 1));
261   tiles.push_back(Vector<int>(getPos().x - 1, getPos().y - 1));
262   tiles.push_back(Vector<int>(getPos().x + 1, getPos().y + 1));
263   tiles.push_back(Vector<int>(getPos().x,     getPos().y + 1));
264   tiles.push_back(Vector<int>(getPos().x - 1, getPos().y + 1));
265   tiles.push_back(Vector<int>(getPos().x + 1, getPos().y));
266   tiles.push_back(Vector<int>(getPos().x - 1, getPos().y));
267
268   int min = -1;
269
270   for (std::vector<Vector<int> >::iterator i = tiles.begin(), end = tiles.end();
271        i != end; ++i)
272     if (is_inside(bounds, *i))
273       {
274         int v = map->getTile(i->x, i->y)->getMoves();
275         if (min == -1)
276           min = v;
277         else
278           min = std::min(min, v);
279       }
280
281   return min;
282 }
283
284 // decrement each armys moves by needed moves to travel
285
286 void Stack::decrementMoves(guint32 moves)
287 {
288   debug("decrement_moves()");
289
290   for (iterator it = begin(); it != end(); it++)
291     {
292       (*it)->decrementMoves(moves);
293     }
294 }
295
296 // Purpose: Return the strongest army of a group
297 // Note: If a hero is present return it. If there are two similar armies
298 // (two of the same strength, or two heroes) return the first in the sequence.
299
300 Army* Stack::getStrongestArmy() const
301 {
302   assert(!empty());
303   return getStrongestArmy(false);
304 }
305
306 Army* Stack::getStrongestHero() const
307 {
308   return getStrongestArmy(true);
309 }
310
311 Army* Stack::getStrongestArmy(bool hero) const
312 {
313   Army *strongest = 0;
314   guint32 highest_strength = 0;
315
316   for (const_iterator it = begin(); it != end(); ++it)
317     {
318       if (((*it)->isHero() && hero) || !hero)
319         {
320           if ((*it)->getStat(Army::STRENGTH) > highest_strength)
321             {
322               highest_strength = (*it)->getStat(Army::STRENGTH);
323               strongest = *it;
324             }
325         }
326     }
327   return strongest;
328 }
329
330 Army *Stack::getArmyById(guint32 id) const
331 {
332   for (Stack::const_iterator i = begin(), e = end(); i != e; ++i)
333     if ((*i)->getId() == id)
334       return *i;
335   
336   return 0;
337 }
338
339 bool Stack::hasHero() const
340 {
341   for (const_iterator it = begin(); it != end(); it++)
342     if ((*it)->isHero())
343       return true;
344
345   return false;
346 }
347
348 Army* Stack::getFirstHero() const
349 {
350   for (const_iterator it = begin(); it != end(); it++)
351     if ((*it)->isHero())
352       return (*it);
353
354   return 0;
355 }
356
357 void Stack::getHeroes(std::vector<guint32>& dst) const
358 {
359   debug("getHeroes - stack = " << this)
360     for (const_iterator it = begin(); it != end(); ++it)
361       {
362         // if hero - add it to the vector
363         debug("Army type: " << (*it)->getTypeId())
364           if ((*it)->isHero() && (*it)->getHP() > 0)
365             dst.push_back((*it)->getId());
366       }
367 }
368
369 int Stack::bless()
370 {
371   int count = 0;
372   for (iterator it = begin(); it != end(); it++)
373     {
374       Temple *temple = GameMap::getTemple(this);
375       if ((*it)->bless(temple))
376         count++;
377     }
378   return count;
379 }
380
381 guint32 Stack::calculateTileMovementCost(Vector<int> pos) const
382 {
383   Maptile* tile = GameMap::getInstance()->getTile(pos);
384   guint32 moves = tile->getMoves();
385   guint32 bonus = calculateMoveBonus();
386   if (bonus & tile->getMaptileType() && moves > 1)
387     moves = 2;
388   else if (isFlying() && moves > 1)
389     moves = 2;
390   return moves;
391 }
392
393 Vector<int> Stack::getFirstPointInPath() const
394 {
395   if (d_path->size() == 0)
396     return Vector<int>(-1,-1);
397   Vector<int> p = *(d_path->begin());
398   return p;
399 }
400
401 Vector<int> Stack::getLastReachablePointInPath() const
402 {
403   if (d_path->size() == 0)
404     return Vector<int>(-1,-1);
405   unsigned int count = 0;
406   for (Path::iterator it = d_path->begin(); it != d_path->end(); it++)
407     {
408       count++;
409       if (count == d_path->getMovesExhaustedAtPoint())
410         return (*it);
411     }
412   return Vector<int>(-1,-1);
413 }
414 Vector<int> Stack::getLastPointInPath() const
415 {
416   if (d_path->size() == 0)
417     return Vector<int>(-1,-1);
418   Vector<int> p = d_path->back();
419   return p;
420 }
421
422 bool Stack::enoughMoves() const
423 {
424   if (d_path->size() == 0)
425     return true; //we have enough moves to move nowhere!
426
427   Vector<int> p = getFirstPointInPath();
428   guint32 needed = calculateTileMovementCost(p);
429
430   if (getMoves() >= needed)
431     return true;
432
433   return false;
434 }
435
436 bool Stack::canMove() const
437 {
438   int tile_moves = getMinTileMoves();
439   int group_moves = getMoves();
440
441   assert (tile_moves != -1);
442   return group_moves > 0 && tile_moves >= 0 && group_moves >= tile_moves;
443 }
444
445 guint32 Stack::getMaxSight() const
446 {
447   guint32 max = 0;
448   for (const_iterator it = begin(); it != end(); it++)
449     if ((*it)->getStat(Army::SIGHT) > max)
450       max = (*it)->getStat(Army::SIGHT);
451
452   return max;
453 }
454
455 void Stack::payUpkeep(Player *p)
456 {
457   for (iterator it = begin(); it != end(); ++it)
458       p->withdrawGold((*it)->getUpkeep());
459 }
460
461 void Stack::nextTurn()
462 {
463   guint32 movement_multiplier = 1;
464   setParked(false);
465
466   //count the number of items that double the movement in the stack.
467   for (const_iterator it = begin(); it != end(); it++)
468     if ((*it)->isHero())
469       {
470         Hero *hero = dynamic_cast<Hero*>(*it);
471         guint32 bonus = hero->getBackpack()->countMovementDoublers();
472         for (guint32 i = 0; i < bonus; i++)
473           movement_multiplier*=2;
474       }
475
476   //set the multipler on all armies in the stack
477   for (const_iterator it = begin(); it != end(); it++)
478     (*it)->setStat(Army::MOVES_MULTIPLIER, movement_multiplier);
479
480   if (d_defending == true)
481     setFortified(true);
482
483   for (iterator it = begin(); it != end(); ++it)
484     {
485       (*it)->resetMoves();
486       (*it)->heal();
487     }
488
489   //recalculate paths
490
491   d_path->recalculate(this);
492
493 }
494
495 bool Stack::save(XML_Helper* helper) const
496 {
497   bool retval = true;
498
499   retval &= helper->openTag(Stack::d_tag);
500   retval &= helper->saveData("id", d_id);
501   retval &= helper->saveData("x", getPos().x);
502   retval &= helper->saveData("y", getPos().y);
503   if (d_owner)
504     retval &= helper->saveData("owner", d_owner->getId());
505   else
506     retval &= helper->saveData("owner", -1);
507   retval &= helper->saveData("defending", d_defending);
508   retval &= helper->saveData("parked", d_parked);
509
510
511   //save path
512   retval &= d_path->save(helper);
513
514   //save armies
515   for (const_iterator it = begin(); it != end(); it++)
516     retval &= (*it)->save(helper);
517
518   retval &= helper->closeTag();
519
520   return retval;
521 }
522
523 bool Stack::load(std::string tag, XML_Helper* helper)
524 {
525   if (tag == Path::d_tag)
526     {
527       d_path = new Path(helper);
528
529       return true;
530     }
531
532   if (tag == Army::d_tag)
533     {
534       Army* a = new Army(helper);
535       a->setOwner(d_owner);
536       push_back(a);
537
538       return true;
539     }
540
541   if (tag == Hero::d_tag)
542     {
543       Hero* h = new Hero(helper);
544       h->setOwner(d_owner);
545       push_back(h);
546
547       return true;
548     }
549
550   return false;
551 }
552
553 void Stack::flClear()
554 {
555   for (iterator it = begin(); it != end(); it++)
556     delete (*it);
557   clear();
558 }
559
560 Stack::iterator Stack::flErase(Stack::iterator object)
561 {
562   delete (*object);
563   return erase(object);
564 }
565
566 guint32 Stack::calculateMoveBonus() const
567 {
568   guint32 d_bonus = 0;
569
570   bool landed = false;
571   guint32 bonus;
572   // check to see if we're all flying
573   int num_landedhero = 0;
574   int num_flyer = 0;
575   int num_landedother = 0;
576   if (size() == 0)
577     return 0;
578   for (const_iterator it = this->begin(); it != this->end(); it++)
579     {
580       bonus = (*it)->getStat(Army::MOVE_BONUS);
581       if (bonus == Tile::GRASS || (bonus & Tile::WATER) == 0 || 
582           (bonus & Tile::FOREST) == 0 || (bonus & Tile::HILLS) == 0 ||
583           (bonus & Tile::MOUNTAIN) == 0 || (bonus & Tile::SWAMP) == 0)
584         {
585           landed = true;
586           if ((*it)->isHero())
587             num_landedhero++;
588           else
589             num_landedother++;
590         }
591       else
592         num_flyer++;
593
594     }
595   //if we're all flying or we have enough flyers to carry landbound heroes
596   if (landed == false ||
597       (num_landedother == 0 && num_landedhero <= num_flyer)) 
598     {
599       d_bonus = Tile::isFlying();
600       return d_bonus;
601     }
602
603   //or maybe we have an item that lets us all fly
604   for (const_iterator it = begin(); it != end(); it++)
605     {
606       if ((*it)->isHero())
607         {
608           Hero *h = dynamic_cast<Hero*>(*it);
609           if (h->getBackpack()->countStackFlightGivers() > 0)
610             {
611               d_bonus = Tile::isFlying();
612               return d_bonus;
613             }
614         }
615     }
616
617   //calculate move bonuses for non-flying stacks
618   for (Stack::const_iterator it = this->begin(); it != this->end(); it++)
619     {
620       bonus = (*it)->getStat(Army::MOVE_BONUS);
621
622       //only forest and hills extend to all other units in the stack
623       d_bonus |= bonus & (Tile::HILLS | Tile::FOREST);
624
625     }
626   return d_bonus;
627 }
628
629 bool Stack::isFlying () const
630 {
631   guint32 d_bonus = calculateMoveBonus();
632   if (d_bonus == Tile::isFlying())
633     return true;
634   else
635     return false;
636 }
637
638 /*if any stack member is in a boat, then the whole stack appears to be in
639  * a boat */
640 bool Stack::hasShip () const
641 {
642   for (Stack::const_iterator it = this->begin(); it != this->end(); it++)
643     {
644       if ((*it)->getStat(Army::SHIP))
645         return true;
646     }
647   return false;
648 }
649
650 guint32 getFightOrder(std::list<guint32> values, guint32 value)
651 {
652   guint32 count = 0;
653   for (std::list<guint32>::const_iterator it = values.begin(); 
654        it != values.end(); it++)
655     {
656       count++;
657       if (count == value)
658         return (*it);
659     }
660   return 0;
661 }
662
663 bool Stack::armyCompareStrength (const Army *lhs, const Army *rhs)  
664 {
665   return lhs->getStat(Army::STRENGTH) < rhs->getStat(Army::STRENGTH);
666 }
667
668 bool Stack::armyCompareFightOrder (const Army *lhs, const Army *rhs)  
669 {
670   std::list<guint32> lhs_fight_order = lhs->getOwner()->getFightOrder();
671   std::list<guint32> rhs_fight_order = rhs->getOwner()->getFightOrder();
672   guint32 lhs_rank = getFightOrder (lhs_fight_order, lhs->getTypeId());
673   guint32 rhs_rank = getFightOrder (rhs_fight_order, rhs->getTypeId());
674   return lhs_rank < rhs_rank; 
675 }
676
677 void Stack::sortByStrength(bool reverse)
678 {
679   sort(armyCompareStrength);
680   if (reverse)
681     std::reverse(begin(), end());
682 }
683
684 void Stack::sortForViewing (bool reverse)
685 {
686   sort(armyCompareFightOrder);
687   if (reverse)
688     std::reverse(begin(), end());
689 }
690
691 void Stack::setFortified(bool fortified)
692 {
693   if (empty())
694     return;
695   for (iterator it = begin(); it != end(); it++)
696     (*it)->setFortified(false);
697
698   (*begin())->setFortified(fortified);
699 }
700
701 bool Stack::getFortified() const
702 {
703   if (empty())
704     return false;
705   for (const_iterator it = begin(); it != end(); it++)
706     {
707       if ((*it)->getFortified())
708         return true;
709     }
710   return false;
711 }
712
713 guint32 Stack::getUpkeep() const
714 {
715   guint32 upkeep = 0;
716   for (const_iterator it = begin(); it != end(); it++)
717     upkeep += (*it)->getUpkeep();
718   return upkeep;
719 }
720
721 guint32 Stack::getMaxArmiesToJoin() const
722 {
723   return MAX_STACK_SIZE - size();
724 }
725
726 bool Stack::canJoin(const Stack *stack) const
727 {
728   if ((stack->size() + size()) > MAX_STACK_SIZE)
729     return false;
730
731   return true;
732
733 }
734
735 //take the weakest units where their strengths add up to strength.
736 std::list<guint32> Stack::determineArmiesByStrength(bool strongest, float strength) const
737 {
738   std::list<guint32> armies;
739   float remaining = strength; 
740   Stack *stack = new Stack(*this);
741   stack->sortByStrength(false);
742   for (iterator it = stack->begin(); it != stack->end(); it++)
743     {
744       float score = AI_Analysis::assessArmyStrength(*it);
745       if (score > remaining)
746         continue;
747       else
748         {
749           remaining -= score;
750           armies.push_back((*it)->getId());
751         }
752     }
753   delete stack;
754   return armies;
755 }
756
757 std::list<guint32> Stack::determineStrongArmies(float strength) const
758 {
759   return determineArmiesByStrength(true, strength);
760 }
761 std::list<guint32> Stack::determineWeakArmies(float strength) const
762 {
763   return determineArmiesByStrength(false, strength);
764 }
765
766 std::list<guint32> Stack::determineReachableArmies(Vector<int> dest) const
767 {
768   std::list<guint32> ids;
769   //try each army individually to see if it reaches
770           
771   Stack *stack = Stack::createNonUniqueStack(getOwner(), getPos());
772   for (const_iterator it = begin(); it != end(); it++)
773     {
774       if ((*it)->getMoves() > 0)
775         {
776           stack->push_back(*it);
777           if (stack->getMoves() >= stack->getPath()->calculate(stack, dest))
778             ids.push_back((*it)->getId());
779           stack->clear();
780         }
781     }
782   delete stack;
783   if (ids.size() == 0)
784     return ids;
785
786   //now try to see if any army units can tag along
787   stack = Stack::createNonUniqueStack(getOwner(), getPos());
788   for (const_iterator it = begin(); it != end(); it++)
789     {
790       //skip over armies that are already known to be reachable
791       if (find(ids.begin(), ids.end(), (*it)->getId()) != ids.end())
792         continue;
793       if ((*it)->getMoves() > 0)
794         {
795           stack->push_back(*it);
796           //also push back the rest of the known reachables
797           std::list<guint32>::iterator iit = ids.begin();
798           for (; iit != ids.end(); iit++)
799             {
800               Army *army = getArmyById(*iit);
801               if (army)
802                 stack->push_back(army);
803             }
804           if (stack->getMoves() >= 
805               stack->getPath()->calculate(stack, dest))
806             ids.push_back((*it)->getId());
807           stack->clear();
808         }
809     }
810   delete stack;
811
812   return ids;
813 }
814
815 guint32 Stack::countArmiesBlessedAtTemple(guint32 temple_id) const
816 {
817   guint32 blessed = 0;
818   for (const_iterator it = begin(); it != end(); it++)
819     {
820       if ((*it)->blessedAtTemple(temple_id))
821         blessed++;
822     }
823     return blessed;
824 }
825         
826 Stack* Stack::createNonUniqueStack(Player *player, Vector<int> pos)
827 {
828   return new Stack(0, player, pos);
829 }
830
831 guint32 Stack::getMaxLandMoves() const
832 {
833   if (empty())
834     return 0;
835
836   assert(!empty());
837
838   //copy the stack, reset the moves and return the group moves
839   Stack *copy = new Stack (*this);
840   copy->getPath()->clear(); //this prevents triggering path recalc in nextTurn
841   copy->decrementMoves(copy->getMoves());
842   copy->nextTurn();
843   guint32 moves = copy->getMoves();
844   if (isFlying() == true)
845     {
846       delete copy;
847       return moves;
848     }
849
850   //alright, we're not flying.  what would our group moves be if we were on land
851   //remove ship status from all army units
852   copy->decrementMoves(copy->getMoves());
853   for (Stack::iterator it = copy->begin(); it != copy->end(); it++)
854     (*it)->setInShip(false);
855   copy->nextTurn();
856
857   moves = copy->getMoves();
858   delete copy;
859   return moves;
860 }
861
862 guint32 Stack::getMaxBoatMoves() const
863 {
864   if (empty())
865     return 0;
866
867   assert(!empty());
868
869   //copy the stack, reset the moves and return the group moves
870   Stack *copy = new Stack (*this);
871   copy->getPath()->clear(); //this prevents triggering path recalc in nextTurn
872   copy->nextTurn();
873   guint32 moves = copy->getMoves();
874   if (isFlying() == true)
875     {
876       delete copy;
877       return moves;
878     }
879   //alright, we're not flying.  what would our group moves be if we were on water?
880   copy->decrementMoves(copy->getMoves());
881               
882   for (Stack::iterator it = copy->begin(); it != copy->end(); it++)
883     {
884       if (((*it)->getStat(Army::MOVE_BONUS) & Tile::WATER) == 0)
885         (*it)->setInShip(true);
886       else
887         (*it)->setInShip(false);
888     }
889   copy->nextTurn();
890
891   moves = copy->getMoves();
892   delete copy;
893   return moves;
894 }
895         
896 void Stack::setPath(const Path p)
897 {
898   if (d_path)
899     delete d_path;
900   d_path = new Path(p);
901 }
902
903 void Stack::add(Army *army)
904 {
905   push_back(army);
906 }
907
908 //! split the given army from this stack, into a brand new stack.
909 Stack *Stack::splitArmy(Army *army)
910 {
911   if (size() == 1) //we can't split the last army.
912     return NULL;
913
914   assert (army != NULL);
915   Stack *new_stack = NULL;
916   for (iterator it = begin(); it != end(); it++)
917     {
918       if (*it == army || (*it)->getId() == army->getId())
919         {
920           new_stack = new Stack(getOwner(), getPos());
921           new_stack->add(*it);
922           it = erase(it);
923           break;
924         }
925     }
926
927   return new_stack;
928 }
929
930 //! split the given armies from this stack, into a brand new stack.
931 Stack *Stack::splitArmies(std::list<Army*> armies)
932 {
933   std::list<guint32> ids;
934   for (std::list<Army*>::iterator i = armies.begin(); i != armies.end(); i++)
935     ids.push_back((*i)->getId());
936   return splitArmies(ids);
937 }
938
939 Stack *Stack::splitArmies(std::list<guint32> armies)
940 {
941   if (armies.size() == 0) //we can't split 0 armies into a new stack.
942     return NULL;
943   if (armies.size() >= size()) //we can't split everyone into a new stack.
944     return NULL;
945   Stack *new_stack = NULL;
946   for (std::list<guint32>::iterator i = armies.begin(); i != armies.end(); i++)
947     {
948       bool found = false;
949       iterator found_army_it = end();
950       for (iterator it = begin(); it != end(); it++)
951         {
952           if ((*it)->getId() == *i)
953             {
954               found = true;
955               found_army_it = it;
956               break;
957             }
958         }
959       if (found)
960         {
961           if (new_stack == NULL)
962             new_stack = new Stack(getOwner(), getPos());
963           new_stack->push_back(*found_army_it);
964           erase(found_army_it);
965         }
966     }
967   return new_stack;
968 }
969 //! split the armies in the stack that this much mp or more into a new stack.
970 Stack *Stack::splitArmiesWithMovement(guint32 mp)
971 {
972   std::list<Army*> armies;
973   for (iterator it = begin(); it != end(); it++)
974     if ((*it)->getMoves() >= mp)
975       armies.push_back(*it);
976   return splitArmies(armies);
977 }
978
979 void Stack::join(Stack *join)
980 {
981   for (iterator i = join->begin(); i != join->end(); i++)
982     push_back(*i);
983   join->clear();
984 }
985
986 bool Stack::validate() const
987 {
988   if (size() > MAX_STACK_SIZE)
989     return false;
990   if (size() == 0)
991     return false;
992   return true;
993 }
994
995 bool Stack::isFull() const
996 {
997   if (size() >= MAX_STACK_SIZE)
998     return true;
999   return false;
1000 }
1001
1002 bool Stack::clearPath()
1003 {
1004   if (getPath())
1005     {
1006       if (getPath()->size() > 0)
1007         {
1008           getPath()->clear();
1009           return true;
1010         }
1011       else
1012         return false;
1013     }
1014   else
1015     return false;
1016   return true;
1017 }
1018
1019 bool Stack::isOnCity() const
1020 {
1021   if (GameMap::getInstance()->getBuilding(getPos()) == Maptile::CITY)
1022     return true;
1023   return false;
1024 }
1025
1026 bool Stack::hasPath() const
1027 {
1028   if (getPath() && getPath()->size() > 0)
1029     return true;
1030   return false;
1031 }
1032
1033 bool Stack::hasQuest() const
1034 {
1035   for (const_iterator it = begin(); it != end(); it++)
1036     {
1037       if ((*it)->isHero() == true)
1038         {
1039           Hero *hero = dynamic_cast<Hero*>(*it);
1040           if (hero->hasQuest() == true)
1041             return true;
1042
1043         }
1044     }
1045   return false;
1046 }
1047
1048 bool Stack::hasArmyType(guint32 army_type) const
1049 {
1050   for (const_iterator it = begin(); it != end(); it++)
1051     {
1052       if ((*it)->getTypeId() == army_type)
1053         return true;
1054     }
1055   return false;
1056 }
1057
1058 guint32 Stack::countAllies() const
1059 {
1060   guint32 count = 0;
1061   for (const_iterator it = begin(); it != end(); it++)
1062     {
1063       if ((*it)->getAwardable() == true)
1064         count++;
1065     }
1066   return count;
1067 }
1068
1069 Hero *Stack::getFirstHeroWithoutAQuest() const
1070 {
1071   Hero *hero = NULL;
1072   for (const_iterator it = begin(); it != end(); it++)
1073     {
1074       if ((*it)->isHero() == false)
1075         continue;
1076       hero = dynamic_cast<Hero*>(*it);
1077       if (hero->hasQuest() == false)
1078         return hero;
1079     }
1080   return NULL;
1081 }
1082
1083 Hero *Stack::getFirstHeroWithAQuest() const
1084 {
1085   Hero *hero = NULL;
1086   for (const_iterator it = begin(); it != end(); it++)
1087     {
1088       if ((*it)->isHero() == false)
1089         continue;
1090       hero = dynamic_cast<Hero*>(*it);
1091       if (hero->hasQuest() == true)
1092         return hero;
1093     }
1094   return NULL;
1095 }
1096 // End of file