1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2005 Andrea Paternesi
4 // Copyright (C) 2004 John Farrell
5 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
6 // Copyright (C) 2007, 2008 Ole Laursen
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.
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.
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
25 #include <sigc++/functors/mem_fun.h>
26 #include <sigc++/adaptors/bind.h>
30 #include "stacklist.h"
34 #include "playerlist.h"
35 #include "xmlhelper.h"
39 #include "LocationList.h"
41 #include "stacktile.h"
43 std::string Stacklist::d_tag = "stacklist";
46 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
49 Vector<int> Stacklist::getPosition(guint32 id)
51 for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
52 pit != Playerlist::getInstance()->end(); pit++)
54 Stacklist* mylist = (*pit)->getStacklist();
55 for (const_iterator it = mylist->begin(); it !=mylist->end(); it++)
56 for (Stack::const_iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
57 if ((*sit)->getId() == id)
58 return (*it)->getPos();
61 return Vector<int>(-1,-1);
64 //We only expect one ambiguity at a time with stacks of the same player. This
65 //never happens except when a stack comes to halt on another stack during
67 //It also happens when two stacks fight.
68 Stack* Stacklist::getAmbiguity(Stack* s)
70 return GameMap::getInstance()->getTile(s->getPos())->getStacks()->getOtherStack(s);
73 //search all player's stacklists to find this stack
74 bool Stacklist::deleteStack(Stack* s)
76 for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
77 pit != Playerlist::getInstance()->end(); pit++)
79 Stacklist* mylist = (*pit)->getStacklist();
80 for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
82 return mylist->flRemove(s);
86 bool Stacklist::deleteStack(guint32 id)
88 for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
89 pit != Playerlist::getInstance()->end(); pit++)
91 Stacklist* mylist = (*pit)->getStacklist();
92 for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
93 if ((*it)->getId() == id)
94 return mylist->flRemove(*it);
99 void Stacklist::payUpkeep(Player *p)
101 for (iterator it = begin(); it != end(); it++)
105 void Stacklist::nextTurn()
108 for (iterator it = begin(); it != end(); it++)
112 for (iterator it = begin(); it != end(); it++)
113 for (iterator jit = begin(); jit != end(); jit++)
115 if ((*jit)->getId() == (*it)->getId())
117 fprintf (stderr, "duplicate army id %d found\n", (*it)->getId());
122 vector<Stack*> Stacklist::getDefendersInCity(const City *city)
124 debug("getDefendersInCity()");
126 vector<Stack*> stackvector;
127 Vector<int> pos = city->getPos();
129 for (unsigned int i = pos.x; i < pos.x + city->getSize(); i++)
131 for (unsigned int j = pos.y; j < pos.y + city->getSize(); j++)
133 Vector<int> p = Vector<int>(i,j);
134 std::list<Stack *>stacks =
135 GameMap::getFriendlyStacks(p, city->getOwner());
136 for (std::list<Stack*>::iterator it = stacks.begin();
137 it != stacks.end(); it++)
138 stackvector.push_back(*it);
145 unsigned int Stacklist::getNoOfStacks()
147 unsigned int mysize = 0;
149 for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
150 pit != Playerlist::getInstance()->end(); pit++)
152 mysize += (*pit)->getStacklist()->size();
158 unsigned int Stacklist::getNoOfArmies()
160 unsigned int mysize = 0;
162 for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
163 pit != Playerlist::getInstance()->end(); pit++)
165 mysize += (*pit)->getStacklist()->countArmies();
171 unsigned int Stacklist::countArmies() const
173 unsigned int mysize = 0;
175 for (const_iterator it = begin(); it != end(); it++)
176 mysize += (*it)->size();
181 unsigned int Stacklist::countAllies() const
183 unsigned int mysize = 0;
185 for (const_iterator it = begin(); it != end(); it++)
187 mysize += (*it)->countAllies();
193 Stacklist::Stacklist()
198 Stacklist::Stacklist(Stacklist *stacklist)
201 for (iterator it = stacklist->begin(); it != stacklist->end(); it++)
203 add(new Stack(**it));
207 Stacklist::Stacklist(XML_Helper* helper)
210 helper->registerTag(Stack::d_tag, sigc::mem_fun((*this), &Stacklist::load));
212 load(Stacklist::d_tag, helper);
215 Stacklist::~Stacklist()
217 //disconnect the signals
218 for (ConnectionMap::iterator it = d_connections.begin();
219 it != d_connections.end(); it++)
221 std::list<sigc::connection> list = (*it).second;
222 for (std::list<sigc::connection>::iterator lit = list.begin(); lit != list.end(); lit++)
225 for (Stacklist::iterator it = begin(); it != end(); it++)
232 Stack* Stacklist::getNextMovable() const
234 Player *player = Playerlist::getInstance()->getActiveplayer();
236 const_iterator it = begin();
238 //first, if we already have an active stack, loop through until we meet it
241 for (; *it != d_activestack; it++);
242 it++; //we want to start with the next stack :)
245 //continue looping until we meet the next not defending stack of this player
246 for (; it != end(); ++it)
249 if (s->getOwner() == player && !s->getDefending() &&
250 !s->getParked() && s->canMove())
254 //still not found a stack? Then start looping from the beginning until we
255 //meet the activestack again. If there is no activestack, we have already
256 //looped through the whole list, so stop here
260 for (it = begin(); *it != d_activestack; ++it)
263 if (s->getOwner() == player && !s->getDefending() &&
264 !s->getParked() && s->canMove())
268 //still there? well, then we have only one stack left.
269 if (d_activestack->getDefending() || d_activestack->getParked())
272 return d_activestack;
275 Stack *Stacklist::getStackById(guint32 id) const
277 IdMap::const_iterator it = d_id.find(id);
278 if (it != d_id.end())
284 Stack *Stacklist::getArmyStackById(guint32 army) const
286 for (Stacklist::const_iterator i = begin(), e = end(); i != e; ++i)
287 if ((*i)->getArmyById(army))
293 void Stacklist::flClear()
297 for (iterator it = begin(); it != end(); it++)
305 Stacklist::iterator Stacklist::flErase(iterator object)
307 if (d_activestack == (*object))
310 return erase(object);
313 bool Stacklist::flRemove(guint32 id)
315 Stack *s = getStackById(id);
321 bool Stacklist::flRemove(Stack* object)
325 debug("removing stack with id " << object->getId() << endl);
326 iterator stackit = find(begin(), end(), object);
327 if (stackit != end())
329 if (d_activestack == object)
331 assert (object->getId() == (*stackit)->getId());
332 deletePositionFromMap(object);
341 bool Stacklist::save(XML_Helper* helper) const
345 retval &= helper->openTag(Stacklist::d_tag);
347 retval &= helper->saveData("active", d_activestack->getId());
349 retval &= helper->saveData("active", 0);
352 for (const_iterator it = begin(); it != end(); it++)
353 retval &= (*it)->save(helper);
355 retval &= helper->closeTag();
360 bool Stacklist::enoughMoves() const
362 for (const_iterator it = begin(); it != end(); it++)
365 if (!s->getPath()->empty() && s->enoughMoves())
372 bool Stacklist::load(string tag, XML_Helper* helper)
374 static guint32 active = 0;
376 if (tag == Stacklist::d_tag)
378 helper->getData(active, "active");
382 if (tag == Stack::d_tag)
384 Stack* s = new Stack(helper);
385 if (active != 0 && s->getId() == active)
395 void Stacklist::getHeroes(std::vector<guint32>& dst) const
397 for (Stacklist::const_iterator it = begin(); it != end(); it++)
398 (*it)->getHeroes(dst);
401 void Stacklist::collectTaxes(Player *p, guint32 num_cities) const
403 std::vector<guint32> hero_ids;
406 //now let's see if we have any items that give us gold per city
407 for (std::vector<guint32>::iterator it = hero_ids.begin();
408 it != hero_ids.end(); it++)
410 Stack *stack = getArmyStackById(*it);
411 Army *army = stack->getArmyById(*it);
412 Hero *hero = static_cast<Hero*>(army);
413 guint32 bonus = hero->getBackpack()->countGoldBonuses();
414 p->addGold(bonus * num_cities);
418 // do we have enough movement points to get to a place on our path
419 // where we can drop the stack on a suitable tile?
420 //suitable = empty tile, or
421 //a tile with a friendly stack that has a small enough stack to merge with
422 //we're currently at a tile prior to a stack that's too big.
423 //problem point: getting into a boat.
425 bool Stacklist::canJumpOverTooLargeStack(Stack *s)
428 guint32 mp = s->getMoves();
429 for (Path::iterator it = s->getPath()->begin(); it != s->getPath()->end(); it++)
431 guint32 moves = s->calculateTileMovementCost(*it);
435 if (GameMap::getEnemyCity(*it) != NULL)
437 if (GameMap::getEnemyStack(*it) != NULL)
439 if (GameMap::canJoin(s, *it) == true)
445 std::list<Hero*> Stacklist::getHeroes() const
447 std::list<Hero*> heroes;
448 std::vector<guint32> hero_ids;
450 for (std::vector<guint32>::const_iterator it = hero_ids.begin();
451 it != hero_ids.end(); it++)
453 Stack *s = getArmyStackById(*it);
456 Hero *h = dynamic_cast<Hero*>(s->getArmyById(*it));
464 Hero *Stacklist::getNearestHero(Vector<int> pos, int dist) const
466 std::list<Hero*> heroes = getHeroes();
467 LocationList<Location*> hero_locales;
468 for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end(); it++)
470 hero_locales.push_back(new Location(getPosition((*it)->getId()), 1));
472 Location *hero_locale = hero_locales.getNearestObjectBefore(pos, dist);
475 for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end();
478 if (getPosition((*it)->getId()) == hero_locale->getPos())
485 bool Stacklist::addPositionToMap(Stack *stack)
487 snewpos.emit(stack, stack->getPos());
491 bool Stacklist::deletePositionFromMap(Stack *stack)
493 soldpos.emit(stack, stack->getPos());
497 void Stacklist::add(Stack *stack)
500 d_id[stack->getId()] = stack;
501 if (stack->getPos() != Vector<int>(-1,-1))
503 bool added = addPositionToMap(stack);
506 std::list<sigc::connection> conn;
507 conn.push_back(stack->smoving.connect
508 (sigc::mem_fun (this, &Stacklist::on_stack_starts_moving)));
509 conn.push_back(stack->smoved.connect
510 (sigc::mem_fun (this, &Stacklist::on_stack_stops_moving)));
511 conn.push_back(stack->sdying.connect
512 (sigc::mem_fun (this, &Stacklist::on_stack_died)));
513 conn.push_back(stack->sgrouped.connect
514 (sigc::mem_fun (this, &Stacklist::on_stack_grouped)));
515 d_connections[stack] = conn;
519 void Stacklist::on_stack_grouped (Stack *stack, bool grouped)
521 sgrouped.emit(stack, grouped);
523 void Stacklist::on_stack_died (Stack *stack)
525 deletePositionFromMap(stack);
526 ConnectionMap::iterator it = d_connections.find(stack);
527 if (it != d_connections.end())
529 std::list<sigc::connection> list = (*it).second;
530 for (std::list<sigc::connection>::iterator lit = list.begin(); lit != list.end(); lit++)
533 d_id.erase(d_id.find(stack->getId()));
536 void Stacklist::on_stack_starts_moving (Stack *stack)
538 deletePositionFromMap(stack);
541 void Stacklist::on_stack_stops_moving (Stack *stack)
543 addPositionToMap(stack);
546 void Stacklist::setActivestack(Stack* activestack)
548 d_activestack = activestack;
551 void Stacklist::drainAllMovement()
553 for (iterator it = begin(); it != end(); it++)
554 for (Stack::iterator ait = (*it)->begin(); ait != (*it)->end(); ait++)
555 (*ait)->decrementMoves((*ait)->getMoves());
558 void Stacklist::changeOwnership(Stack *stack, Player *new_owner)
560 if (new_owner != stack->getOwner())
562 Stack *new_stack = new Stack(*stack);
563 stack->getOwner()->getStacklist()->flRemove(stack);
564 new_owner->addStack(new_stack);
568 std::list<Vector<int> > Stacklist::getPositions() const
570 std::list<Vector<int> > points;
571 for (const_iterator it = begin(); it != end(); it++)
573 if (std::find(points.begin(), points.end(), (*it)->getPos()) ==
575 points.push_back((*it)->getPos());