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
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.
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.
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
24 #include <sigc++/functors/mem_fun.h>
29 #include "playerlist.h"
31 #include "armysetlist.h"
37 #include "xmlhelper.h"
41 #include "AI_Analysis.h"
43 std::string Stack::d_tag = "stack";
46 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
49 Stack::Stack(Player* player, Vector<int> pos)
50 : UniquelyIdentified(), Movable(pos), Ownable(player), d_defending(false),
51 d_parked(false), d_deleting(false)
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)
63 Stack::Stack(const Stack& s)
64 : UniquelyIdentified(s), Movable(s), Ownable(s),
65 d_defending(s.d_defending), d_parked(s.d_parked),
70 printf("Stack %d has a null path!\n", d_id);
72 d_path = new Path(*s.d_path);
74 for (const_iterator sit = s.begin(); sit != s.end(); sit++)
78 Army *h = new Hero(dynamic_cast<Hero&>(**sit));
83 Army *a = new Army((**sit), (*sit)->getOwner());
89 Stack::Stack(XML_Helper* helper)
90 : UniquelyIdentified(helper), Movable(helper), Ownable(helper),
93 helper->getData(d_defending, "defending");
94 helper->getData(d_parked, "parked");
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));
111 void Stack::setPlayer(Player* p)
113 // we need to change the armies' loyalties as well!!
115 for (iterator it = begin(); it != end(); it++)
119 void Stack::moveOneStep(bool skipping)
121 debug("moveOneStep()");
123 Vector<int> dest = getFirstPointInPath();
124 moveToDest(dest, skipping);
126 //now remove first point of the path
127 d_path->eraseFirstPoint();
130 bool Stack::isMovingToOrFromAShip(Vector<int> dest, bool &on_ship) const
132 Vector<int> pos = getPos();
134 bool to_city = GameMap::getInstance()->getBuilding(dest) == Maptile::CITY;
135 bool on_city = GameMap::getInstance()->getBuilding(pos) == Maptile::CITY;
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 &&
152 (!on_water && !to_water && on_ship == true))
160 void Stack::moveToDest(Vector<int> dest, bool skipping)
162 bool ship_load_unload = false;
165 bool on_ship = hasShip();
166 if (isMovingToOrFromAShip(dest, on_ship) == true)
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()
175 for (Stack::iterator it = begin(); it != end(); it++)
178 ((*it)->getStat(Army::MOVE_BONUS) & Tile::WATER) == 0)
179 (*it)->setInShip(true);
181 (*it)->setInShip(false);
188 for (Stack::iterator it = begin(); it != end(); it++)
189 (*it)->setInShip(false);
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);
196 for (Stack::iterator it = begin(); it != end(); it++)
198 if (ship_load_unload)
199 (*it)->decrementMoves((*it)->getMoves());
202 //maybe the army has a natural movement ability
203 if ((*it)->getStat(Army::MOVE_BONUS) & maptype && needed_moves > 1)
204 (*it)->decrementMoves(2);
206 (*it)->decrementMoves(needed_moves);
210 //update position and status
225 getOwner()->getFogMap()->alterFogRadius(getPos(), getMaxSight(),
230 // return the maximum moves of this stack by checking the moves of each army
231 guint32 Stack::getMoves() const
240 for (const_iterator it = begin(); it != end(); ++it)
243 min = int((*it)->getMoves());
245 min = std::min(min, int((*it)->getMoves()));
253 int Stack::getMinTileMoves() const
255 GameMap *map = GameMap::getInstance();
256 Rectangle bounds = map->get_boundary();
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));
270 for (std::vector<Vector<int> >::iterator i = tiles.begin(), end = tiles.end();
272 if (is_inside(bounds, *i))
274 int v = map->getTile(i->x, i->y)->getMoves();
278 min = std::min(min, v);
284 // decrement each armys moves by needed moves to travel
286 void Stack::decrementMoves(guint32 moves)
288 debug("decrement_moves()");
290 for (iterator it = begin(); it != end(); it++)
292 (*it)->decrementMoves(moves);
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.
300 Army* Stack::getStrongestArmy() const
303 return getStrongestArmy(false);
306 Army* Stack::getStrongestHero() const
308 return getStrongestArmy(true);
311 Army* Stack::getStrongestArmy(bool hero) const
314 guint32 highest_strength = 0;
316 for (const_iterator it = begin(); it != end(); ++it)
318 if (((*it)->isHero() && hero) || !hero)
320 if ((*it)->getStat(Army::STRENGTH) > highest_strength)
322 highest_strength = (*it)->getStat(Army::STRENGTH);
330 Army *Stack::getArmyById(guint32 id) const
332 for (Stack::const_iterator i = begin(), e = end(); i != e; ++i)
333 if ((*i)->getId() == id)
339 bool Stack::hasHero() const
341 for (const_iterator it = begin(); it != end(); it++)
348 Army* Stack::getFirstHero() const
350 for (const_iterator it = begin(); it != end(); it++)
357 void Stack::getHeroes(std::vector<guint32>& dst) const
359 debug("getHeroes - stack = " << this)
360 for (const_iterator it = begin(); it != end(); ++it)
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());
372 for (iterator it = begin(); it != end(); it++)
374 Temple *temple = GameMap::getTemple(this);
375 if ((*it)->bless(temple))
381 guint32 Stack::calculateTileMovementCost(Vector<int> pos) const
383 Maptile* tile = GameMap::getInstance()->getTile(pos);
384 guint32 moves = tile->getMoves();
385 guint32 bonus = calculateMoveBonus();
386 if (bonus & tile->getMaptileType() && moves > 1)
388 else if (isFlying() && moves > 1)
393 Vector<int> Stack::getFirstPointInPath() const
395 if (d_path->size() == 0)
396 return Vector<int>(-1,-1);
397 Vector<int> p = *(d_path->begin());
401 Vector<int> Stack::getLastReachablePointInPath() const
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++)
409 if (count == d_path->getMovesExhaustedAtPoint())
412 return Vector<int>(-1,-1);
414 Vector<int> Stack::getLastPointInPath() const
416 if (d_path->size() == 0)
417 return Vector<int>(-1,-1);
418 Vector<int> p = d_path->back();
422 bool Stack::enoughMoves() const
424 if (d_path->size() == 0)
425 return true; //we have enough moves to move nowhere!
427 Vector<int> p = getFirstPointInPath();
428 guint32 needed = calculateTileMovementCost(p);
430 if (getMoves() >= needed)
436 bool Stack::canMove() const
438 int tile_moves = getMinTileMoves();
439 int group_moves = getMoves();
441 assert (tile_moves != -1);
442 return group_moves > 0 && tile_moves >= 0 && group_moves >= tile_moves;
445 guint32 Stack::getMaxSight() const
448 for (const_iterator it = begin(); it != end(); it++)
449 if ((*it)->getStat(Army::SIGHT) > max)
450 max = (*it)->getStat(Army::SIGHT);
455 void Stack::payUpkeep(Player *p)
457 for (iterator it = begin(); it != end(); ++it)
458 p->withdrawGold((*it)->getUpkeep());
461 void Stack::nextTurn()
463 guint32 movement_multiplier = 1;
466 //count the number of items that double the movement in the stack.
467 for (const_iterator it = begin(); it != end(); it++)
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;
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);
480 if (d_defending == true)
483 for (iterator it = begin(); it != end(); ++it)
491 d_path->recalculate(this);
495 bool Stack::save(XML_Helper* helper) const
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);
504 retval &= helper->saveData("owner", d_owner->getId());
506 retval &= helper->saveData("owner", -1);
507 retval &= helper->saveData("defending", d_defending);
508 retval &= helper->saveData("parked", d_parked);
512 retval &= d_path->save(helper);
515 for (const_iterator it = begin(); it != end(); it++)
516 retval &= (*it)->save(helper);
518 retval &= helper->closeTag();
523 bool Stack::load(std::string tag, XML_Helper* helper)
525 if (tag == Path::d_tag)
527 d_path = new Path(helper);
532 if (tag == Army::d_tag)
534 Army* a = new Army(helper);
535 a->setOwner(d_owner);
541 if (tag == Hero::d_tag)
543 Hero* h = new Hero(helper);
544 h->setOwner(d_owner);
553 void Stack::flClear()
555 for (iterator it = begin(); it != end(); it++)
560 Stack::iterator Stack::flErase(Stack::iterator object)
563 return erase(object);
566 guint32 Stack::calculateMoveBonus() const
572 // check to see if we're all flying
573 int num_landedhero = 0;
575 int num_landedother = 0;
578 for (const_iterator it = this->begin(); it != this->end(); it++)
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)
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))
599 d_bonus = Tile::isFlying();
603 //or maybe we have an item that lets us all fly
604 for (const_iterator it = begin(); it != end(); it++)
608 Hero *h = dynamic_cast<Hero*>(*it);
609 if (h->getBackpack()->countStackFlightGivers() > 0)
611 d_bonus = Tile::isFlying();
617 //calculate move bonuses for non-flying stacks
618 for (Stack::const_iterator it = this->begin(); it != this->end(); it++)
620 bonus = (*it)->getStat(Army::MOVE_BONUS);
622 //only forest and hills extend to all other units in the stack
623 d_bonus |= bonus & (Tile::HILLS | Tile::FOREST);
629 bool Stack::isFlying () const
631 guint32 d_bonus = calculateMoveBonus();
632 if (d_bonus == Tile::isFlying())
638 /*if any stack member is in a boat, then the whole stack appears to be in
640 bool Stack::hasShip () const
642 for (Stack::const_iterator it = this->begin(); it != this->end(); it++)
644 if ((*it)->getStat(Army::SHIP))
650 guint32 getFightOrder(std::list<guint32> values, guint32 value)
653 for (std::list<guint32>::const_iterator it = values.begin();
654 it != values.end(); it++)
663 bool Stack::armyCompareStrength (const Army *lhs, const Army *rhs)
665 return lhs->getStat(Army::STRENGTH) < rhs->getStat(Army::STRENGTH);
668 bool Stack::armyCompareFightOrder (const Army *lhs, const Army *rhs)
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;
677 void Stack::sortByStrength(bool reverse)
679 sort(armyCompareStrength);
681 std::reverse(begin(), end());
684 void Stack::sortForViewing (bool reverse)
686 sort(armyCompareFightOrder);
688 std::reverse(begin(), end());
691 void Stack::setFortified(bool fortified)
695 for (iterator it = begin(); it != end(); it++)
696 (*it)->setFortified(false);
698 (*begin())->setFortified(fortified);
701 bool Stack::getFortified() const
705 for (const_iterator it = begin(); it != end(); it++)
707 if ((*it)->getFortified())
713 guint32 Stack::getUpkeep() const
716 for (const_iterator it = begin(); it != end(); it++)
717 upkeep += (*it)->getUpkeep();
721 guint32 Stack::getMaxArmiesToJoin() const
723 return MAX_STACK_SIZE - size();
726 bool Stack::canJoin(const Stack *stack) const
728 if ((stack->size() + size()) > MAX_STACK_SIZE)
735 //take the weakest units where their strengths add up to strength.
736 std::list<guint32> Stack::determineArmiesByStrength(bool strongest, float strength) const
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++)
744 float score = AI_Analysis::assessArmyStrength(*it);
745 if (score > remaining)
750 armies.push_back((*it)->getId());
757 std::list<guint32> Stack::determineStrongArmies(float strength) const
759 return determineArmiesByStrength(true, strength);
761 std::list<guint32> Stack::determineWeakArmies(float strength) const
763 return determineArmiesByStrength(false, strength);
766 std::list<guint32> Stack::determineReachableArmies(Vector<int> dest) const
768 std::list<guint32> ids;
769 //try each army individually to see if it reaches
771 Stack *stack = Stack::createNonUniqueStack(getOwner(), getPos());
772 for (const_iterator it = begin(); it != end(); it++)
774 if ((*it)->getMoves() > 0)
776 stack->push_back(*it);
777 if (stack->getMoves() >= stack->getPath()->calculate(stack, dest))
778 ids.push_back((*it)->getId());
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++)
790 //skip over armies that are already known to be reachable
791 if (find(ids.begin(), ids.end(), (*it)->getId()) != ids.end())
793 if ((*it)->getMoves() > 0)
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++)
800 Army *army = getArmyById(*iit);
802 stack->push_back(army);
804 if (stack->getMoves() >=
805 stack->getPath()->calculate(stack, dest))
806 ids.push_back((*it)->getId());
815 guint32 Stack::countArmiesBlessedAtTemple(guint32 temple_id) const
818 for (const_iterator it = begin(); it != end(); it++)
820 if ((*it)->blessedAtTemple(temple_id))
826 Stack* Stack::createNonUniqueStack(Player *player, Vector<int> pos)
828 return new Stack(0, player, pos);
831 guint32 Stack::getMaxLandMoves() const
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());
843 guint32 moves = copy->getMoves();
844 if (isFlying() == true)
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);
857 moves = copy->getMoves();
862 guint32 Stack::getMaxBoatMoves() const
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
873 guint32 moves = copy->getMoves();
874 if (isFlying() == true)
879 //alright, we're not flying. what would our group moves be if we were on water?
880 copy->decrementMoves(copy->getMoves());
882 for (Stack::iterator it = copy->begin(); it != copy->end(); it++)
884 if (((*it)->getStat(Army::MOVE_BONUS) & Tile::WATER) == 0)
885 (*it)->setInShip(true);
887 (*it)->setInShip(false);
891 moves = copy->getMoves();
896 void Stack::setPath(const Path p)
900 d_path = new Path(p);
903 void Stack::add(Army *army)
908 //! split the given army from this stack, into a brand new stack.
909 Stack *Stack::splitArmy(Army *army)
911 if (size() == 1) //we can't split the last army.
914 assert (army != NULL);
915 Stack *new_stack = NULL;
916 for (iterator it = begin(); it != end(); it++)
918 if (*it == army || (*it)->getId() == army->getId())
920 new_stack = new Stack(getOwner(), getPos());
930 //! split the given armies from this stack, into a brand new stack.
931 Stack *Stack::splitArmies(std::list<Army*> armies)
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);
939 Stack *Stack::splitArmies(std::list<guint32> armies)
941 if (armies.size() == 0) //we can't split 0 armies into a new stack.
943 if (armies.size() >= size()) //we can't split everyone into a new stack.
945 Stack *new_stack = NULL;
946 for (std::list<guint32>::iterator i = armies.begin(); i != armies.end(); i++)
949 iterator found_army_it = end();
950 for (iterator it = begin(); it != end(); it++)
952 if ((*it)->getId() == *i)
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);
969 //! split the armies in the stack that this much mp or more into a new stack.
970 Stack *Stack::splitArmiesWithMovement(guint32 mp)
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);
979 void Stack::join(Stack *join)
981 for (iterator i = join->begin(); i != join->end(); i++)
986 bool Stack::validate() const
988 if (size() > MAX_STACK_SIZE)
995 bool Stack::isFull() const
997 if (size() >= MAX_STACK_SIZE)
1002 bool Stack::clearPath()
1006 if (getPath()->size() > 0)
1019 bool Stack::isOnCity() const
1021 if (GameMap::getInstance()->getBuilding(getPos()) == Maptile::CITY)
1026 bool Stack::hasPath() const
1028 if (getPath() && getPath()->size() > 0)
1033 bool Stack::hasQuest() const
1035 for (const_iterator it = begin(); it != end(); it++)
1037 if ((*it)->isHero() == true)
1039 Hero *hero = dynamic_cast<Hero*>(*it);
1040 if (hero->hasQuest() == true)
1048 bool Stack::hasArmyType(guint32 army_type) const
1050 for (const_iterator it = begin(); it != end(); it++)
1052 if ((*it)->getTypeId() == army_type)
1058 guint32 Stack::countAllies() const
1061 for (const_iterator it = begin(); it != end(); it++)
1063 if ((*it)->getAwardable() == true)
1069 Hero *Stack::getFirstHeroWithoutAQuest() const
1072 for (const_iterator it = begin(); it != end(); it++)
1074 if ((*it)->isHero() == false)
1076 hero = dynamic_cast<Hero*>(*it);
1077 if (hero->hasQuest() == false)
1083 Hero *Stack::getFirstHeroWithAQuest() const
1086 for (const_iterator it = begin(); it != end(); it++)
1088 if ((*it)->isHero() == false)
1090 hero = dynamic_cast<Hero*>(*it);
1091 if (hero->hasQuest() == true)