--- /dev/null
+// Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
+// Copyright (C) 2004, 2005 Andrea Paternesi
+// Copyright (C) 2004 John Farrell
+// Copyright (C) 2007, 2008, 2009 Ben Asselstine
+// Copyright (C) 2007, 2008 Ole Laursen
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Library General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "config.h"
+#include "signal.h"
+#include <sigc++/functors/mem_fun.h>
+#include <sigc++/adaptors/bind.h>
+#include <assert.h>
+#include <algorithm>
+
+#include "stacklist.h"
+#include "stack.h"
+#include "city.h"
+#include "path.h"
+#include "playerlist.h"
+#include "xmlhelper.h"
+#include "Item.h"
+#include "hero.h"
+#include "Backpack.h"
+#include "LocationList.h"
+#include "GameMap.h"
+#include "stacktile.h"
+
+std::string Stacklist::d_tag = "stacklist";
+using namespace std;
+
+//#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
+#define debug(x)
+
+Vector<int> Stacklist::getPosition(guint32 id)
+{
+ for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
+ pit != Playerlist::getInstance()->end(); pit++)
+ {
+ Stacklist* mylist = (*pit)->getStacklist();
+ for (const_iterator it = mylist->begin(); it !=mylist->end(); it++)
+ for (Stack::const_iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
+ if ((*sit)->getId() == id)
+ return (*it)->getPos();
+ }
+
+ return Vector<int>(-1,-1);
+}
+
+//We only expect one ambiguity at a time with stacks of the same player. This
+//never happens except when a stack comes to halt on another stack during
+//long movements
+//It also happens when two stacks fight.
+Stack* Stacklist::getAmbiguity(Stack* s)
+{
+ return GameMap::getInstance()->getTile(s->getPos())->getStacks()->getOtherStack(s);
+}
+
+//search all player's stacklists to find this stack
+bool Stacklist::deleteStack(Stack* s)
+{
+ for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
+ pit != Playerlist::getInstance()->end(); pit++)
+ {
+ Stacklist* mylist = (*pit)->getStacklist();
+ for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
+ if ((*it) == s)
+ return mylist->flRemove(s);
+ }
+ return false;
+}
+bool Stacklist::deleteStack(guint32 id)
+{
+ for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
+ pit != Playerlist::getInstance()->end(); pit++)
+ {
+ Stacklist* mylist = (*pit)->getStacklist();
+ for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
+ if ((*it)->getId() == id)
+ return mylist->flRemove(*it);
+ }
+ return false;
+}
+
+void Stacklist::payUpkeep(Player *p)
+{
+ for (iterator it = begin(); it != end(); it++)
+ (*it)->payUpkeep(p);
+}
+
+void Stacklist::nextTurn()
+{
+ debug("nextTurn()");
+ for (iterator it = begin(); it != end(); it++)
+ {
+ (*it)->nextTurn();
+ }
+ for (iterator it = begin(); it != end(); it++)
+ for (iterator jit = begin(); jit != end(); jit++)
+ if (*jit != *it)
+ if ((*jit)->getId() == (*it)->getId())
+ {
+ fprintf (stderr, "duplicate army id %d found\n", (*it)->getId());
+ exit (1);
+ }
+}
+
+vector<Stack*> Stacklist::getDefendersInCity(const City *city)
+{
+ debug("getDefendersInCity()");
+
+ vector<Stack*> stackvector;
+ Vector<int> pos = city->getPos();
+
+ for (unsigned int i = pos.x; i < pos.x + city->getSize(); i++)
+ {
+ for (unsigned int j = pos.y; j < pos.y + city->getSize(); j++)
+ {
+ Vector<int> p = Vector<int>(i,j);
+ std::list<Stack *>stacks =
+ GameMap::getFriendlyStacks(p, city->getOwner());
+ for (std::list<Stack*>::iterator it = stacks.begin();
+ it != stacks.end(); it++)
+ stackvector.push_back(*it);
+ }
+ }
+
+ return stackvector;
+}
+
+unsigned int Stacklist::getNoOfStacks()
+{
+ unsigned int mysize = 0;
+
+ for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
+ pit != Playerlist::getInstance()->end(); pit++)
+ {
+ mysize += (*pit)->getStacklist()->size();
+ }
+
+ return mysize;
+}
+
+unsigned int Stacklist::getNoOfArmies()
+{
+ unsigned int mysize = 0;
+
+ for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
+ pit != Playerlist::getInstance()->end(); pit++)
+ {
+ mysize += (*pit)->getStacklist()->countArmies();
+ }
+
+ return mysize;
+}
+
+unsigned int Stacklist::countArmies() const
+{
+ unsigned int mysize = 0;
+
+ for (const_iterator it = begin(); it != end(); it++)
+ mysize += (*it)->size();
+
+ return mysize;
+}
+
+unsigned int Stacklist::countAllies() const
+{
+ unsigned int mysize = 0;
+
+ for (const_iterator it = begin(); it != end(); it++)
+ {
+ mysize += (*it)->countAllies();
+ }
+
+ return mysize;
+}
+
+Stacklist::Stacklist()
+ :d_activestack(0)
+{
+}
+
+Stacklist::Stacklist(Stacklist *stacklist)
+ :d_activestack(0)
+{
+ for (iterator it = stacklist->begin(); it != stacklist->end(); it++)
+ {
+ add(new Stack(**it));
+ }
+}
+
+Stacklist::Stacklist(XML_Helper* helper)
+ :d_activestack(0)
+{
+ helper->registerTag(Stack::d_tag, sigc::mem_fun((*this), &Stacklist::load));
+
+ load(Stacklist::d_tag, helper);
+}
+
+Stacklist::~Stacklist()
+{
+ //disconnect the signals
+ for (ConnectionMap::iterator it = d_connections.begin();
+ it != d_connections.end(); it++)
+ {
+ std::list<sigc::connection> list = (*it).second;
+ for (std::list<sigc::connection>::iterator lit = list.begin(); lit != list.end(); lit++)
+ (*lit).disconnect();
+ }
+ for (Stacklist::iterator it = begin(); it != end(); it++)
+ {
+ it = flErase(it);
+ }
+
+}
+
+Stack* Stacklist::getNextMovable() const
+{
+ Player *player = Playerlist::getInstance()->getActiveplayer();
+
+ const_iterator it = begin();
+
+ //first, if we already have an active stack, loop through until we meet it
+ if (d_activestack)
+ {
+ for (; *it != d_activestack; it++);
+ it++; //we want to start with the next stack :)
+ }
+
+ //continue looping until we meet the next not defending stack of this player
+ for (; it != end(); ++it)
+ {
+ Stack *s = *it;
+ if (s->getOwner() == player && !s->getDefending() &&
+ !s->getParked() && s->canMove())
+ return s;
+ }
+
+ //still not found a stack? Then start looping from the beginning until we
+ //meet the activestack again. If there is no activestack, we have already
+ //looped through the whole list, so stop here
+ if (!d_activestack)
+ return 0;
+
+ for (it = begin(); *it != d_activestack; ++it)
+ {
+ Stack *s = *it;
+ if (s->getOwner() == player && !s->getDefending() &&
+ !s->getParked() && s->canMove())
+ return s;
+ }
+
+ //still there? well, then we have only one stack left.
+ if (d_activestack->getDefending() || d_activestack->getParked())
+ return 0;
+ else
+ return d_activestack;
+}
+
+Stack *Stacklist::getStackById(guint32 id) const
+{
+ IdMap::const_iterator it = d_id.find(id);
+ if (it != d_id.end())
+ return (*it).second;
+ else
+ return NULL;
+}
+
+Stack *Stacklist::getArmyStackById(guint32 army) const
+{
+ for (Stacklist::const_iterator i = begin(), e = end(); i != e; ++i)
+ if ((*i)->getArmyById(army))
+ return *i;
+
+ return 0;
+}
+
+void Stacklist::flClear()
+{
+ d_activestack = 0;
+
+ for (iterator it = begin(); it != end(); it++)
+ {
+ delete (*it);
+ }
+
+ clear();
+}
+
+Stacklist::iterator Stacklist::flErase(iterator object)
+{
+ if (d_activestack == (*object))
+ d_activestack = 0;
+ delete (*object);
+ return erase(object);
+}
+
+bool Stacklist::flRemove(guint32 id)
+{
+ Stack *s = getStackById(id);
+ if (s == NULL)
+ return false;
+ return flRemove(s);
+}
+
+bool Stacklist::flRemove(Stack* object)
+{
+ if (object == NULL)
+ return false;
+ debug("removing stack with id " << object->getId() << endl);
+ iterator stackit = find(begin(), end(), object);
+ if (stackit != end())
+ {
+ if (d_activestack == object)
+ d_activestack = 0;
+ assert (object->getId() == (*stackit)->getId());
+ deletePositionFromMap(object);
+ delete object;
+ erase(stackit);
+ return true;
+ }
+
+ return false;
+}
+
+bool Stacklist::save(XML_Helper* helper) const
+{
+ bool retval = true;
+
+ retval &= helper->openTag(Stacklist::d_tag);
+ if (d_activestack)
+ retval &= helper->saveData("active", d_activestack->getId());
+ else
+ retval &= helper->saveData("active", 0);
+
+ //save stacks
+ for (const_iterator it = begin(); it != end(); it++)
+ retval &= (*it)->save(helper);
+
+ retval &= helper->closeTag();
+
+ return retval;
+}
+
+bool Stacklist::enoughMoves() const
+{
+ for (const_iterator it = begin(); it != end(); it++)
+ {
+ Stack* s = *it;
+ if (!s->getPath()->empty() && s->enoughMoves())
+ return true;
+ }
+
+ return false;
+}
+
+bool Stacklist::load(string tag, XML_Helper* helper)
+{
+ static guint32 active = 0;
+
+ if (tag == Stacklist::d_tag)
+ {
+ helper->getData(active, "active");
+ return true;
+ }
+
+ if (tag == Stack::d_tag)
+ {
+ Stack* s = new Stack(helper);
+ if (active != 0 && s->getId() == active)
+ d_activestack = s;
+
+ add(s);
+ return true;
+ }
+
+ return false;
+}
+
+void Stacklist::getHeroes(std::vector<guint32>& dst) const
+{
+ for (Stacklist::const_iterator it = begin(); it != end(); it++)
+ (*it)->getHeroes(dst);
+}
+
+void Stacklist::collectTaxes(Player *p, guint32 num_cities) const
+{
+ std::vector<guint32> hero_ids;
+ getHeroes(hero_ids);
+
+ //now let's see if we have any items that give us gold per city
+ for (std::vector<guint32>::iterator it = hero_ids.begin();
+ it != hero_ids.end(); it++)
+ {
+ Stack *stack = getArmyStackById(*it);
+ Army *army = stack->getArmyById(*it);
+ Hero *hero = static_cast<Hero*>(army);
+ guint32 bonus = hero->getBackpack()->countGoldBonuses();
+ p->addGold(bonus * num_cities);
+ }
+}
+
+// do we have enough movement points to get to a place on our path
+// where we can drop the stack on a suitable tile?
+//suitable = empty tile, or
+//a tile with a friendly stack that has a small enough stack to merge with
+//we're currently at a tile prior to a stack that's too big.
+//problem point: getting into a boat.
+
+bool Stacklist::canJumpOverTooLargeStack(Stack *s)
+{
+ bool found = false;
+ guint32 mp = s->getMoves();
+ for (Path::iterator it = s->getPath()->begin(); it != s->getPath()->end(); it++)
+ {
+ guint32 moves = s->calculateTileMovementCost(*it);
+ if (moves > mp)
+ return false;
+ mp -= moves;
+ if (GameMap::getEnemyCity(*it) != NULL)
+ return false;
+ if (GameMap::getEnemyStack(*it) != NULL)
+ return false;
+ if (GameMap::canJoin(s, *it) == true)
+ return true;
+ }
+ return found;
+}
+
+std::list<Hero*> Stacklist::getHeroes() const
+{
+ std::list<Hero*> heroes;
+ std::vector<guint32> hero_ids;
+ getHeroes(hero_ids);
+ for (std::vector<guint32>::const_iterator it = hero_ids.begin();
+ it != hero_ids.end(); it++)
+ {
+ Stack *s = getArmyStackById(*it);
+ if (s)
+ {
+ Hero *h = dynamic_cast<Hero*>(s->getArmyById(*it));
+ if (h)
+ heroes.push_back(h);
+ }
+ }
+ return heroes;
+}
+
+Hero *Stacklist::getNearestHero(Vector<int> pos, int dist) const
+{
+ std::list<Hero*> heroes = getHeroes();
+ LocationList<Location*> hero_locales;
+ for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end(); it++)
+ {
+ hero_locales.push_back(new Location(getPosition((*it)->getId()), 1));
+ }
+ Location *hero_locale = hero_locales.getNearestObjectBefore(pos, dist);
+ if (hero_locale)
+ {
+ for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end();
+ it++)
+ {
+ if (getPosition((*it)->getId()) == hero_locale->getPos())
+ return (*it);
+ }
+ }
+ return NULL;
+}
+
+bool Stacklist::addPositionToMap(Stack *stack)
+{
+ snewpos.emit(stack, stack->getPos());
+ return true;
+}
+
+bool Stacklist::deletePositionFromMap(Stack *stack)
+{
+ soldpos.emit(stack, stack->getPos());
+ return true;
+}
+
+void Stacklist::add(Stack *stack)
+{
+ push_back(stack);
+ d_id[stack->getId()] = stack;
+ if (stack->getPos() != Vector<int>(-1,-1))
+ {
+ bool added = addPositionToMap(stack);
+ if (!added)
+ assert(1 == 0);
+ std::list<sigc::connection> conn;
+ conn.push_back(stack->smoving.connect
+ (sigc::mem_fun (this, &Stacklist::on_stack_starts_moving)));
+ conn.push_back(stack->smoved.connect
+ (sigc::mem_fun (this, &Stacklist::on_stack_stops_moving)));
+ conn.push_back(stack->sdying.connect
+ (sigc::mem_fun (this, &Stacklist::on_stack_died)));
+ conn.push_back(stack->sgrouped.connect
+ (sigc::mem_fun (this, &Stacklist::on_stack_grouped)));
+ d_connections[stack] = conn;
+ }
+}
+
+void Stacklist::on_stack_grouped (Stack *stack, bool grouped)
+{
+ sgrouped.emit(stack, grouped);
+}
+void Stacklist::on_stack_died (Stack *stack)
+{
+ deletePositionFromMap(stack);
+ ConnectionMap::iterator it = d_connections.find(stack);
+ if (it != d_connections.end())
+ {
+ std::list<sigc::connection> list = (*it).second;
+ for (std::list<sigc::connection>::iterator lit = list.begin(); lit != list.end(); lit++)
+ (*lit).disconnect();
+ }
+ d_id.erase(d_id.find(stack->getId()));
+ return;
+}
+void Stacklist::on_stack_starts_moving (Stack *stack)
+{
+ deletePositionFromMap(stack);
+ return;
+}
+void Stacklist::on_stack_stops_moving (Stack *stack)
+{
+ addPositionToMap(stack);
+ return;
+}
+void Stacklist::setActivestack(Stack* activestack)
+{
+ d_activestack = activestack;
+}
+
+void Stacklist::drainAllMovement()
+{
+ for (iterator it = begin(); it != end(); it++)
+ for (Stack::iterator ait = (*it)->begin(); ait != (*it)->end(); ait++)
+ (*ait)->decrementMoves((*ait)->getMoves());
+}
+
+void Stacklist::changeOwnership(Stack *stack, Player *new_owner)
+{
+ if (new_owner != stack->getOwner())
+ {
+ Stack *new_stack = new Stack(*stack);
+ stack->getOwner()->getStacklist()->flRemove(stack);
+ new_owner->addStack(new_stack);
+ }
+}
+
+std::list<Vector<int> > Stacklist::getPositions() const
+{
+ std::list<Vector<int> > points;
+ for (const_iterator it = begin(); it != end(); it++)
+ {
+ if (std::find(points.begin(), points.end(), (*it)->getPos()) ==
+ points.end())
+ points.push_back((*it)->getPos());
+ }
+ return points;
+
+}
+// End of file