initial commit, lordsawar source, slightly modified
[lordsawar] / src / stacklist.cpp
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
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 "config.h"
24 #include "signal.h"
25 #include <sigc++/functors/mem_fun.h>
26 #include <sigc++/adaptors/bind.h>
27 #include <assert.h>
28 #include <algorithm>
29
30 #include "stacklist.h"
31 #include "stack.h"
32 #include "city.h"
33 #include "path.h"
34 #include "playerlist.h"
35 #include "xmlhelper.h"
36 #include "Item.h"
37 #include "hero.h"
38 #include "Backpack.h"
39 #include "LocationList.h"
40 #include "GameMap.h"
41 #include "stacktile.h"
42
43 std::string Stacklist::d_tag = "stacklist";
44 using namespace std;
45
46 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
47 #define debug(x)
48
49 Vector<int> Stacklist::getPosition(guint32 id)
50 {
51     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
52         pit != Playerlist::getInstance()->end(); pit++)
53     {
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();
59     }
60
61     return Vector<int>(-1,-1);
62 }
63
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
66 //long movements
67 //It also happens when two stacks fight.
68 Stack* Stacklist::getAmbiguity(Stack* s)
69 {
70   return GameMap::getInstance()->getTile(s->getPos())->getStacks()->getOtherStack(s);
71 }
72
73 //search all player's stacklists to find this stack
74 bool Stacklist::deleteStack(Stack* s)
75 {
76     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
77         pit != Playerlist::getInstance()->end(); pit++)
78     {
79         Stacklist* mylist = (*pit)->getStacklist();
80         for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
81             if ((*it) == s)
82                 return mylist->flRemove(s);
83     }
84     return false;
85 }
86 bool Stacklist::deleteStack(guint32 id)
87 {
88     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
89         pit != Playerlist::getInstance()->end(); pit++)
90     {
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);
95     }
96     return false;
97 }
98
99 void Stacklist::payUpkeep(Player *p)
100 {
101   for (iterator it = begin(); it != end(); it++)
102     (*it)->payUpkeep(p);
103 }
104
105 void Stacklist::nextTurn()
106 {
107     debug("nextTurn()");
108     for (iterator it = begin(); it != end(); it++)
109       {
110         (*it)->nextTurn();
111       }
112     for (iterator it = begin(); it != end(); it++)
113       for (iterator jit = begin(); jit != end(); jit++)
114         if (*jit != *it)
115           if ((*jit)->getId() == (*it)->getId())
116             {
117               fprintf (stderr, "duplicate army id %d found\n", (*it)->getId());
118               exit (1);
119             }
120 }
121
122 vector<Stack*> Stacklist::getDefendersInCity(const City *city)
123 {
124     debug("getDefendersInCity()");
125
126     vector<Stack*> stackvector;
127     Vector<int> pos = city->getPos();
128
129     for (unsigned int i = pos.x; i < pos.x + city->getSize(); i++)
130     {
131         for (unsigned int j = pos.y; j < pos.y + city->getSize(); j++)
132         {
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);
139         }
140     }
141
142     return stackvector;
143 }
144
145 unsigned int Stacklist::getNoOfStacks()
146 {
147     unsigned int mysize = 0;
148
149     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
150         pit != Playerlist::getInstance()->end(); pit++)
151     {
152         mysize += (*pit)->getStacklist()->size();
153     }
154
155     return mysize;
156 }
157
158 unsigned int Stacklist::getNoOfArmies()
159 {
160     unsigned int mysize = 0;
161
162     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
163         pit != Playerlist::getInstance()->end(); pit++)
164     {
165         mysize += (*pit)->getStacklist()->countArmies();
166     }
167
168     return mysize;
169 }
170
171 unsigned int Stacklist::countArmies() const
172 {
173     unsigned int mysize = 0;
174
175     for (const_iterator it = begin(); it != end(); it++)
176       mysize += (*it)->size();
177
178     return mysize;
179 }
180
181 unsigned int Stacklist::countAllies() const
182 {
183     unsigned int mysize = 0;
184
185     for (const_iterator it = begin(); it != end(); it++)
186       {
187         mysize += (*it)->countAllies();
188       }
189
190     return mysize;
191 }
192
193 Stacklist::Stacklist()
194     :d_activestack(0)
195 {
196 }
197
198 Stacklist::Stacklist(Stacklist *stacklist)
199     :d_activestack(0)
200 {
201     for (iterator it = stacklist->begin(); it != stacklist->end(); it++)
202     {
203         add(new Stack(**it));
204     }
205 }
206
207 Stacklist::Stacklist(XML_Helper* helper)
208     :d_activestack(0)
209 {
210     helper->registerTag(Stack::d_tag, sigc::mem_fun((*this), &Stacklist::load));
211
212     load(Stacklist::d_tag, helper);
213 }
214
215 Stacklist::~Stacklist()
216 {
217   //disconnect the signals
218   for (ConnectionMap::iterator it = d_connections.begin(); 
219        it != d_connections.end(); it++)
220     {
221       std::list<sigc::connection> list = (*it).second;
222       for (std::list<sigc::connection>::iterator lit = list.begin(); lit != list.end(); lit++)
223         (*lit).disconnect();
224     }
225   for (Stacklist::iterator it = begin(); it != end(); it++)
226     {
227       it = flErase(it);
228     }
229
230 }
231
232 Stack* Stacklist::getNextMovable() const
233 {
234     Player *player = Playerlist::getInstance()->getActiveplayer();
235     
236     const_iterator it = begin();
237     
238     //first, if we already have an active stack, loop through until we meet it
239     if (d_activestack)
240     {
241         for (; *it != d_activestack; it++);
242         it++;   //we want to start with the next stack :)
243     }
244
245     //continue looping until we meet the next not defending stack of this player
246     for (; it != end(); ++it)
247     {
248         Stack *s = *it;
249         if (s->getOwner() == player && !s->getDefending() && 
250             !s->getParked() && s->canMove())
251             return s;
252     }
253     
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
257     if (!d_activestack)
258         return 0;
259
260     for (it = begin(); *it != d_activestack; ++it)
261     {
262         Stack *s = *it;
263         if (s->getOwner() == player && !s->getDefending() &&
264             !s->getParked() && s->canMove())
265             return s;
266     }
267
268     //still there? well, then we have only one stack left.
269     if (d_activestack->getDefending() || d_activestack->getParked())
270         return 0;
271     else
272         return d_activestack;
273 }
274
275 Stack *Stacklist::getStackById(guint32 id) const
276 {
277   IdMap::const_iterator it = d_id.find(id);
278   if (it != d_id.end())
279     return (*it).second;
280   else
281     return NULL;
282 }
283
284 Stack *Stacklist::getArmyStackById(guint32 army) const
285 {
286   for (Stacklist::const_iterator i = begin(), e = end(); i != e; ++i)
287     if ((*i)->getArmyById(army))
288       return *i;
289   
290   return 0;
291 }
292
293 void Stacklist::flClear()
294 {
295     d_activestack = 0;
296
297     for (iterator it = begin(); it != end(); it++)
298     {
299         delete (*it);
300     }
301
302     clear();
303 }
304
305 Stacklist::iterator Stacklist::flErase(iterator object)
306 {
307     if (d_activestack == (*object))
308         d_activestack = 0;
309     delete (*object);
310     return erase(object);
311 }
312
313 bool Stacklist::flRemove(guint32 id)
314 {
315   Stack *s = getStackById(id);
316   if (s == NULL)
317     return false;
318   return flRemove(s);
319 }
320
321 bool Stacklist::flRemove(Stack* object)
322 {
323   if (object == NULL)
324     return false;
325     debug("removing stack with id " << object->getId() << endl);
326     iterator stackit = find(begin(), end(), object);
327     if (stackit != end())
328     {
329         if (d_activestack == object)
330             d_activestack = 0;
331         assert (object->getId() == (*stackit)->getId());
332         deletePositionFromMap(object);
333         delete object;
334         erase(stackit);
335         return true;
336     }
337
338     return false;
339 }
340
341 bool Stacklist::save(XML_Helper* helper) const
342 {
343     bool retval = true;
344
345     retval &= helper->openTag(Stacklist::d_tag);
346     if (d_activestack)
347       retval &= helper->saveData("active", d_activestack->getId());
348     else
349       retval &= helper->saveData("active", 0);
350
351     //save stacks
352     for (const_iterator it = begin(); it != end(); it++)
353         retval &= (*it)->save(helper);
354
355     retval &= helper->closeTag();
356
357     return retval;
358 }
359
360 bool Stacklist::enoughMoves() const 
361 {
362     for (const_iterator it = begin(); it != end(); it++)
363     {
364         Stack* s = *it;
365         if (!s->getPath()->empty() && s->enoughMoves())
366             return true;
367     }
368
369     return false;
370 }
371
372 bool Stacklist::load(string tag, XML_Helper* helper)
373 {
374     static guint32 active = 0;
375     
376     if (tag == Stacklist::d_tag)
377     {
378         helper->getData(active, "active");
379         return true;
380     }
381
382     if (tag == Stack::d_tag)
383     {
384         Stack* s = new Stack(helper);
385         if (active != 0 && s->getId() == active)
386           d_activestack = s;
387
388         add(s);
389         return true;
390     }
391
392     return false;
393 }
394
395 void Stacklist::getHeroes(std::vector<guint32>& dst) const
396 {
397   for (Stacklist::const_iterator it = begin(); it != end(); it++)
398     (*it)->getHeroes(dst);
399 }
400
401 void Stacklist::collectTaxes(Player *p, guint32 num_cities) const
402 {
403   std::vector<guint32> hero_ids;
404   getHeroes(hero_ids);
405
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++)
409     {
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);
415     }
416 }
417
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.
424
425 bool Stacklist::canJumpOverTooLargeStack(Stack *s)
426 {
427   bool found = false;
428   guint32 mp = s->getMoves();
429   for (Path::iterator it = s->getPath()->begin(); it != s->getPath()->end(); it++)
430     {
431       guint32 moves = s->calculateTileMovementCost(*it);
432       if (moves > mp)
433         return false;
434       mp -= moves;
435       if (GameMap::getEnemyCity(*it) != NULL)
436         return false;
437       if (GameMap::getEnemyStack(*it) != NULL)
438         return false;
439       if (GameMap::canJoin(s, *it) == true)
440         return true;
441     }
442   return found;
443 }
444
445 std::list<Hero*> Stacklist::getHeroes() const
446 {
447   std::list<Hero*> heroes;
448   std::vector<guint32> hero_ids;
449   getHeroes(hero_ids);
450   for (std::vector<guint32>::const_iterator it = hero_ids.begin(); 
451        it != hero_ids.end(); it++)
452     {
453         Stack *s = getArmyStackById(*it);
454         if (s)
455           {
456             Hero *h = dynamic_cast<Hero*>(s->getArmyById(*it));
457             if (h)
458               heroes.push_back(h);
459           }
460     }
461   return heroes;
462 }
463         
464 Hero *Stacklist::getNearestHero(Vector<int> pos, int dist) const
465 {
466   std::list<Hero*> heroes = getHeroes();
467   LocationList<Location*> hero_locales;
468   for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end(); it++)
469     {
470       hero_locales.push_back(new Location(getPosition((*it)->getId()), 1));
471     }
472   Location *hero_locale = hero_locales.getNearestObjectBefore(pos, dist);
473   if (hero_locale)
474     {
475       for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end(); 
476            it++)
477         {
478           if (getPosition((*it)->getId()) == hero_locale->getPos())
479             return (*it);
480         }
481     }
482   return NULL;
483 }
484
485 bool Stacklist::addPositionToMap(Stack *stack)
486 {
487   snewpos.emit(stack, stack->getPos());
488   return true;
489 }
490
491 bool Stacklist::deletePositionFromMap(Stack *stack)
492 {
493   soldpos.emit(stack, stack->getPos());
494   return true;
495 }
496
497 void Stacklist::add(Stack *stack)
498 {
499   push_back(stack);
500   d_id[stack->getId()] = stack;
501   if (stack->getPos() != Vector<int>(-1,-1))
502     {
503       bool added = addPositionToMap(stack);
504       if (!added)
505         assert(1 == 0);
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;
516     }
517 }
518
519 void Stacklist::on_stack_grouped (Stack *stack, bool grouped)
520 {
521   sgrouped.emit(stack, grouped);
522 }
523 void Stacklist::on_stack_died (Stack *stack)
524 {
525   deletePositionFromMap(stack);
526   ConnectionMap::iterator it = d_connections.find(stack);
527   if (it != d_connections.end())
528     {
529       std::list<sigc::connection> list = (*it).second;
530       for (std::list<sigc::connection>::iterator lit = list.begin(); lit != list.end(); lit++)
531         (*lit).disconnect();
532     }
533   d_id.erase(d_id.find(stack->getId()));
534   return;
535 }
536 void Stacklist::on_stack_starts_moving (Stack *stack)
537 {
538   deletePositionFromMap(stack);
539   return;
540 }
541 void Stacklist::on_stack_stops_moving (Stack *stack)
542 {
543   addPositionToMap(stack);
544   return;
545 }
546 void Stacklist::setActivestack(Stack* activestack)
547 {
548   d_activestack = activestack;
549 }
550
551 void Stacklist::drainAllMovement()
552 {
553   for (iterator it = begin(); it != end(); it++)
554     for (Stack::iterator ait = (*it)->begin(); ait != (*it)->end(); ait++)
555       (*ait)->decrementMoves((*ait)->getMoves());
556 }
557
558 void Stacklist::changeOwnership(Stack *stack, Player *new_owner)
559 {
560   if (new_owner != stack->getOwner())
561     {
562       Stack *new_stack = new Stack(*stack);
563       stack->getOwner()->getStacklist()->flRemove(stack);
564       new_owner->addStack(new_stack);
565     }
566 }
567
568 std::list<Vector<int> > Stacklist::getPositions() const
569 {
570   std::list<Vector<int> > points;
571   for (const_iterator it = begin(); it != end(); it++)
572     {
573       if (std::find(points.begin(), points.end(), (*it)->getPos()) == 
574           points.end())
575         points.push_back((*it)->getPos());
576     }
577   return points;
578
579 }
580 // End of file