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, 2010, 2011, 2014, 2015 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 
29 #include "stacklist.h"
30 #include "stack.h"
31 #include "city.h"
32 #include "path.h"
33 #include "playerlist.h"
34 #include "xmlhelper.h"
35 #include "Item.h"
36 #include "hero.h"
37 #include "Backpack.h"
38 #include "LocationList.h"
39 #include "GameMap.h"
40 #include "stacktile.h"
41 #include "stackreflist.h"
42 
43 Glib::ustring Stacklist::d_tag = "stacklist";
44 
45 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
46 #define debug(x)
47 
getPosition(guint32 id)48 Vector<int> Stacklist::getPosition(guint32 id)
49 {
50     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
51         pit != Playerlist::getInstance()->end(); pit++)
52     {
53         Stacklist* mylist = (*pit)->getStacklist();
54         for (const_iterator it = mylist->begin(); it !=mylist->end(); it++)
55             for (Stack::const_iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
56                 if ((*sit)->getId() == id)
57                     return (*it)->getPos();
58     }
59 
60     return Vector<int>(-1,-1);
61 }
62 
63 //search all player's stacklists to find this stack
deleteStack(Stack * s)64 bool Stacklist::deleteStack(Stack* s)
65 {
66     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
67         pit != Playerlist::getInstance()->end(); pit++)
68     {
69         Stacklist* mylist = (*pit)->getStacklist();
70         for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
71             if ((*it) == s)
72                 return mylist->flRemove(s);
73     }
74     return false;
75 }
76 
deleteStack(guint32 id)77 bool Stacklist::deleteStack(guint32 id)
78 {
79     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
80         pit != Playerlist::getInstance()->end(); pit++)
81     {
82         Stacklist* mylist = (*pit)->getStacklist();
83         for (const_iterator it = mylist->begin(); it != mylist->end(); it++)
84             if ((*it)->getId() == id)
85                 return mylist->flRemove(*it);
86     }
87     return false;
88 }
89 
calculateUpkeep() const90 guint32 Stacklist::calculateUpkeep() const
91 {
92   guint32 upkeep = 0;
93   for (const_iterator it = begin(); it != end(); it++)
94     upkeep += (*it)->getUpkeep();
95   return upkeep;
96 }
97 
payUpkeep(Player * p)98 void Stacklist::payUpkeep(Player *p)
99 {
100   for (iterator it = begin(); it != end(); it++)
101     (*it)->payUpkeep(p);
102 }
103 
check()104 bool Stacklist::check()
105 {
106     for (iterator it = begin(); it != end(); it++)
107       {
108         if ((*it)->getOwner()->isComputer() == false)
109           continue;
110         std::vector<Stack*> f = GameMap::getFriendlyStacks((*it)->getPos());
111         if (f.size() > 1)
112           {
113 	      fprintf (stderr, "%lu stacks found on %d,%d\n", f.size(),
114                        (*it)->getPos().x, (*it)->getPos().y);
115               for (std::vector<Stack*>::iterator t = f.begin(); t != f.end(); t++)
116                 {
117                   Stack *stack = *t;
118                   if (stack)
119                     {
120                     printf("stack id: %d\n", stack->getId());
121                     printf("\tsize is %lu\n", stack->size());
122                     }
123                   else
124                     printf("null stack\n");
125                 }
126               return false;
127           }
128       }
129     return true;
130 }
131 
resetStacks()132 void Stacklist::resetStacks()
133 {
134   for (iterator it = begin(); it != end(); it++)
135     (*it)->reset();
136 }
137 
nextTurn()138 void Stacklist::nextTurn()
139 {
140     debug("nextTurn()");
141     resetStacks();
142 
143     for (iterator it = begin(); it != end(); it++)
144       for (iterator jit = begin(); jit != end(); jit++)
145 	if (*jit != *it)
146 	  if ((*jit)->getId() == (*it)->getId())
147 	    {
148 	      fprintf (stderr, "duplicate army id %d found\n", (*it)->getId());
149 	      exit (1);
150 	    }
151     //printf("checking at next-turn time\n");
152     //check();
153 }
154 
getDefendersInCity(const City * city)155 std::vector<Stack*> Stacklist::getDefendersInCity(const City *city)
156 {
157     debug("getDefendersInCity()");
158 
159     std::vector<Stack*> stackvector;
160     Vector<int> pos = city->getPos();
161 
162     for (unsigned int i = pos.x; i < pos.x + city->getSize(); i++)
163     {
164         for (unsigned int j = pos.y; j < pos.y + city->getSize(); j++)
165         {
166 	    Vector<int> p = Vector<int>(i,j);
167 	    std::vector<Stack *>stacks =
168 	      GameMap::getFriendlyStacks(p, city->getOwner());
169 	    for (std::vector<Stack*>::iterator it = stacks.begin();
170 		 it != stacks.end(); it++)
171 		stackvector.push_back(*it);
172         }
173     }
174 
175     return stackvector;
176 }
177 
getNoOfStacks()178 unsigned int Stacklist::getNoOfStacks()
179 {
180     unsigned int mysize = 0;
181 
182     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
183         pit != Playerlist::getInstance()->end(); pit++)
184       mysize += (*pit)->getStacklist()->size();
185 
186     return mysize;
187 }
188 
getNoOfArmies()189 unsigned int Stacklist::getNoOfArmies()
190 {
191     unsigned int mysize = 0;
192 
193     for (Playerlist::iterator pit = Playerlist::getInstance()->begin();
194         pit != Playerlist::getInstance()->end(); pit++)
195       mysize += (*pit)->getStacklist()->countArmies();
196 
197     return mysize;
198 }
199 
countArmies() const200 unsigned int Stacklist::countArmies() const
201 {
202     unsigned int mysize = 0;
203 
204     for (const_iterator it = begin(); it != end(); it++)
205       mysize += (*it)->size();
206 
207     return mysize;
208 }
209 
Stacklist()210 Stacklist::Stacklist()
211     :d_activestack(0)
212 {
213 }
214 
Stacklist(Stacklist * stacklist)215 Stacklist::Stacklist(Stacklist *stacklist)
216     :d_activestack(0)
217 {
218     for (iterator it = stacklist->begin(); it != stacklist->end(); it++)
219       add(new Stack(**it));
220 }
221 
Stacklist(XML_Helper * helper)222 Stacklist::Stacklist(XML_Helper* helper)
223     :d_activestack(0)
224 {
225     helper->registerTag(Stack::d_tag, sigc::mem_fun((*this), &Stacklist::load));
226     load(Stacklist::d_tag, helper);
227 }
228 
~Stacklist()229 Stacklist::~Stacklist()
230 {
231   //disconnect the signals
232   for (auto it: d_connections)
233     for (auto lit: it.second)
234       lit.disconnect();
235   flClear();
236 }
237 
getNextMovable() const238 Stack* Stacklist::getNextMovable() const
239 {
240     Player *player = Playerlist::getInstance()->getActiveplayer();
241 
242     const_iterator it = begin();
243 
244     //first, if we already have an active stack, loop through until we meet it
245     if (d_activestack)
246     {
247         for (; *it != d_activestack; it++);
248         it++;   //we want to start with the next stack :)
249     }
250 
251     //continue looping until we meet the next not defending stack of this player
252     for (; it != end(); ++it)
253     {
254 	Stack *s = *it;
255         if (s->getOwner() == player && !s->getDefending() &&
256 	    !s->getParked() && s->canMove())
257 	    return s;
258     }
259 
260     //still not found a stack? Then start looping from the beginning until we
261     //meet the activestack again. If there is no activestack, we have already
262     //looped through the whole list, so stop here
263     if (!d_activestack)
264         return 0;
265 
266     for (it = begin(); *it != d_activestack; ++it)
267       {
268         Stack *s = *it;
269         if (s->getOwner() == player && !s->getDefending() &&
270             !s->getParked() && s->canMove())
271           return s;
272       }
273 
274     //still there? well, then we have only one stack left.
275     if (d_activestack->getDefending() || d_activestack->getParked())
276 	return 0;
277     else
278 	return d_activestack;
279 }
280 
getStackById(guint32 id) const281 Stack *Stacklist::getStackById(guint32 id) const
282 {
283   IdMap::const_iterator it = d_id.find(id);
284   if (it != d_id.end())
285     return (*it).second;
286   else
287     return NULL;
288 }
289 
getArmyStackById(guint32 army) const290 Stack *Stacklist::getArmyStackById(guint32 army) const
291 {
292   for (Stacklist::const_iterator i = begin(), e = end(); i != e; ++i)
293     if ((*i)->getArmyById(army))
294       return *i;
295   return NULL;
296 }
297 
flClear()298 void Stacklist::flClear()
299 {
300     d_activestack = 0;
301 
302     for (iterator it = begin(); it != end(); it++)
303       delete (*it);
304 
305     clear();
306 }
307 
flErase(iterator object)308 Stacklist::iterator Stacklist::flErase(iterator object)
309 {
310     if (d_activestack == (*object))
311         d_activestack = 0;
312     delete (*object);
313     return erase(object);
314 }
315 
flRemove(guint32 id)316 bool Stacklist::flRemove(guint32 id)
317 {
318   Stack *s = getStackById(id);
319   if (s == NULL)
320     return false;
321   return flRemove(s);
322 }
323 
flRemove(Stack * object)324 bool Stacklist::flRemove(Stack* object)
325 {
326   if (object == NULL)
327     return false;
328   iterator stackit = find(begin(), end(), object);
329   if (stackit != end())
330     {
331       if (d_activestack == object)
332         d_activestack = 0;
333       assert (object->getId() == (*stackit)->getId());
334       deletePositionFromMap(object);
335       delete object;
336       erase(stackit);
337       return true;
338     }
339 
340   return false;
341 }
342 
save(XML_Helper * helper) const343 bool Stacklist::save(XML_Helper* helper) const
344 {
345     bool retval = true;
346 
347     retval &= helper->openTag(Stacklist::d_tag);
348     if (d_activestack)
349       retval &= helper->saveData("active", d_activestack->getId());
350     else
351       retval &= helper->saveData("active", 0);
352 
353     //save stacks
354     for (const_iterator it = begin(); it != end(); it++)
355         retval &= (*it)->save(helper);
356 
357     retval &= helper->closeTag();
358 
359     return retval;
360 }
361 
enoughMoves() const362 bool Stacklist::enoughMoves() const
363 {
364     for (const_iterator it = begin(); it != end(); it++)
365     {
366         Stack* s = *it;
367         if (!s->getPath()->empty() && s->enoughMoves())
368             return true;
369     }
370 
371     return false;
372 }
373 
load(Glib::ustring tag,XML_Helper * helper)374 bool Stacklist::load(Glib::ustring tag, XML_Helper* helper)
375 {
376     static guint32 active = 0;
377 
378     if (tag == Stacklist::d_tag)
379     {
380         helper->getData(active, "active");
381         return true;
382     }
383 
384     if (tag == Stack::d_tag)
385     {
386         Stack* s = new Stack(helper);
387         if (active != 0 && s->getId() == active)
388 	  d_activestack = s;
389 
390         add(s);
391         return true;
392     }
393 
394     return false;
395 }
396 
getHeroes(std::vector<guint32> & dst) const397 void Stacklist::getHeroes(std::vector<guint32>& dst) const
398 {
399   for (Stacklist::const_iterator it = begin(); it != end(); it++)
400     (*it)->getHeroes(dst);
401 }
402 
collectTaxes(Player * p,guint32 num_cities) const403 void Stacklist::collectTaxes(Player *p, guint32 num_cities) const
404 {
405   std::vector<guint32> hero_ids;
406   getHeroes(hero_ids);
407 
408   //now let's see if we have any items that give us gold per city
409   for (std::vector<guint32>::iterator it = hero_ids.begin();
410        it != hero_ids.end(); it++)
411     {
412       Stack *stack = getArmyStackById(*it);
413       Army *army = stack->getArmyById(*it);
414       Hero *hero = static_cast<Hero*>(army);
415       guint32 bonus = hero->getBackpack()->countGoldBonuses();
416       p->addGold(bonus * num_cities);
417     }
418 }
419 
420 // do we have enough movement points to get to a place on our path
421 // where we can drop the stack on a suitable tile?
422 //suitable = empty tile, or
423 //a tile with a friendly stack that has a small enough stack to merge with
424 //we're currently at a tile prior to a stack that's too big.
425 //problem point: getting into a boat.
426 
canJumpOverTooLargeStack(Stack * s)427 bool Stacklist::canJumpOverTooLargeStack(Stack *s)
428 {
429   bool found = false;
430   guint32 mp = s->getMoves();
431   for (Path::iterator it = s->getPath()->begin(); it != s->getPath()->end(); it++)
432     {
433       guint32 moves = s->calculateTileMovementCost(*it);
434       if (moves > mp)
435 	return false;
436       mp -= moves;
437       City *enemy = GameMap::getEnemyCity(*it);
438       if (enemy != NULL && enemy->isBurnt() == false)
439         return false;
440       if (GameMap::getEnemyStack(*it) != NULL)
441         return false;
442       if (GameMap::canJoin(s, *it) == true)
443 	return true;
444     }
445   return found;
446 }
447 
getHeroes() const448 std::list<Hero*> Stacklist::getHeroes() const
449 {
450   std::list<Hero*> heroes;
451   std::vector<guint32> hero_ids;
452   getHeroes(hero_ids);
453   for (std::vector<guint32>::const_iterator it = hero_ids.begin();
454        it != hero_ids.end(); it++)
455     {
456         Stack *s = getArmyStackById(*it);
457 	if (s)
458 	  {
459 	    Hero *h = dynamic_cast<Hero*>(s->getArmyById(*it));
460 	    if (h)
461 	      heroes.push_back(h);
462 	  }
463     }
464   return heroes;
465 }
466 
getNearestHero(Vector<int> pos,int dist) const467 Hero *Stacklist::getNearestHero(Vector<int> pos, int dist) const
468 {
469   std::list<Hero*> heroes = getHeroes();
470   LocationList<Location*> hero_locales;
471   for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end(); it++)
472     hero_locales.push_back(new Location(getPosition((*it)->getId()), 1));
473   Location *hero_locale = hero_locales.getNearestObjectBefore(pos, dist);
474   if (hero_locale)
475     {
476       for (std::list<Hero*>::iterator it = heroes.begin(); it != heroes.end();
477 	   it++)
478 	{
479 	  if (getPosition((*it)->getId()) == hero_locale->getPos())
480 	    return (*it);
481 	}
482     }
483   return NULL;
484 }
485 
addPositionToMap(Stack * stack) const486 bool Stacklist::addPositionToMap(Stack *stack) const
487 {
488   snewpos.emit(stack, stack->getPos());
489   return true;
490 }
491 
deletePositionFromMap(Stack * stack) const492 bool Stacklist::deletePositionFromMap(Stack *stack) const
493 {
494   soldpos.emit(stack, stack->getPos());
495   return true;
496 }
497 
add(Stack * stack)498 void Stacklist::add(Stack *stack)
499 {
500   push_back(stack);
501   d_id[stack->getId()] = stack;
502   if (stack->getPos() != Vector<int>(-1,-1))
503     {
504       bool added = addPositionToMap(stack);
505       if (!added)
506 	assert(1 == 0);
507       std::list<sigc::connection> conn;
508       conn.push_back(stack->smoving.connect
509 	 (sigc::mem_fun (this, &Stacklist::on_stack_starts_moving)));
510       conn.push_back(stack->smoved.connect
511 	 (sigc::mem_fun (this, &Stacklist::on_stack_stops_moving)));
512       conn.push_back(stack->sdying.connect
513 	 (sigc::mem_fun (this, &Stacklist::on_stack_died)));
514       conn.push_back(stack->sgrouped.connect
515 	 (sigc::mem_fun (this, &Stacklist::on_stack_grouped)));
516       d_connections[stack] = conn;
517     }
518 }
519 
on_stack_grouped(Stack * stack,bool grouped)520 void Stacklist::on_stack_grouped (Stack *stack, bool grouped)
521 {
522   sgrouped.emit(stack, grouped);
523 }
524 
on_stack_died(Stack * stack)525 void Stacklist::on_stack_died (Stack *stack)
526 {
527   deletePositionFromMap(stack);
528   ConnectionMap::iterator it = d_connections.find(stack);
529   if (it != d_connections.end())
530     {
531       for (auto lit: (*it).second)
532 	lit.disconnect();
533     }
534   d_id.erase(d_id.find(stack->getId()));
535   sstackDied.emit ();
536   return;
537 }
on_stack_starts_moving(Stack * stack)538 void Stacklist::on_stack_starts_moving (Stack *stack)
539 {
540   deletePositionFromMap(stack);
541   return;
542 }
on_stack_stops_moving(Stack * stack)543 void Stacklist::on_stack_stops_moving (Stack *stack)
544 {
545   addPositionToMap(stack);
546   return;
547 }
setActivestack(Stack * activestack)548 void Stacklist::setActivestack(Stack* activestack)
549 {
550   d_activestack = activestack;
551 }
552 
drainAllMovement()553 void Stacklist::drainAllMovement()
554 {
555   for (iterator it = begin(); it != end(); it++)
556     (*it)->drainMovement();
557 }
558 
changeOwnership(Player * old_owner,Player * new_owner)559 void Stacklist::changeOwnership(Player *old_owner, Player *new_owner)
560 {
561   StackReflist *stacks = new StackReflist(old_owner->getStacklist());
562   for (StackReflist::iterator it = stacks->begin(); it != stacks->end(); it++)
563     Stacklist::changeOwnership (*it, new_owner);
564   delete stacks;
565 }
566 
changeOwnership(Stack * stack,Player * new_owner)567 Stack* Stacklist::changeOwnership(Stack *stack, Player *new_owner)
568 {
569   if (new_owner != stack->getOwner())
570     {
571       Stack *new_stack = new Stack(*stack);
572       stack->getOwner()->getStacklist()->flRemove(stack);
573       new_owner->addStack(new_stack);
574       return new_stack;
575     }
576   return stack;
577 }
578 
getPositions() const579 std::list<Vector<int> > Stacklist::getPositions() const
580 {
581   std::list<Vector<int> > points;
582   for (const_iterator it = begin(); it != end(); it++)
583     {
584       if (std::find(points.begin(), points.end(), (*it)->getPos()) ==
585           points.end())
586         points.push_back((*it)->getPos());
587     }
588   return points;
589 }
590 
getStacksWithItems() const591 std::list<Stack*> Stacklist::getStacksWithItems() const
592 {
593   std::list<Stack*> stacks;
594   for (const_iterator it = begin(); it != end(); it++)
595     {
596       if ((*it)->countItems() > 0)
597         stacks.push_back((*it));
598     }
599   return stacks;
600 }
601 
kill()602 std::list<Stack*> Stacklist::kill()
603 {
604   std::list<Stack*> stacks;
605   for (iterator it = begin(); it != end(); it++)
606     {
607       (*it)->kill();
608       stacks.push_back(*it);
609     }
610   return stacks;
611 }
612 
killArmyUnitsInBoats()613 std::list<Stack*> Stacklist::killArmyUnitsInBoats()
614 {
615   std::list<Stack*> stacks;
616   for (iterator it = begin(); it != end(); it++)
617     {
618       if ((*it)->hasShip())
619         {
620           if ((*it)->killArmyUnitsInBoats())
621             stacks.push_back(*it);
622         }
623     }
624   return stacks;
625 }
626 
killArmies(guint32 army_type)627 std::list<Stack*> Stacklist::killArmies(guint32 army_type)
628 {
629   std::list<Stack*> stacks;
630   for (iterator it = begin(); it != end(); it++)
631     {
632       if ((*it)->killArmies(army_type))
633         stacks.push_back(*it);
634     }
635   return stacks;
636 }
637 
getUsableItems() const638 std::list<Item*> Stacklist::getUsableItems() const
639 {
640   std::list<Item*> items;
641   for (const_iterator it = begin(); it != end(); it++)
642     {
643       if ((*it)->hasUsableItem())
644         (*it)->getUsableItems(items);
645     }
646   return items;
647 }
648 
hasUsableItem() const649 bool Stacklist::hasUsableItem() const
650 {
651   for (const_iterator it = begin(); it != end(); it++)
652     {
653       if ((*it)->hasUsableItem())
654         return true;
655     }
656   return false;
657 }
658 
getItemHolder(Item * item,Stack ** stack,Hero ** hero) const659 bool Stacklist::getItemHolder(Item *item, Stack **stack, Hero **hero) const
660 {
661   for (const_iterator it = begin(); it != end(); it++)
662     {
663       *hero = (*it)->getHeroWithItem(item);
664       if (*hero != NULL)
665         {
666           *stack = *it;
667           return true;
668         }
669     }
670   return false;
671 }
672 
countMovableStacks() const673 guint32 Stacklist::countMovableStacks() const
674 {
675   guint32 count = 0;
676   for (const_iterator i = begin(); i != end(); i++)
677     {
678       if (!(*i)->getParked() && (*i)->canMove())
679         {
680           if ((*i)->getPath()->size() > 0 && (*i)->enoughMoves())
681             count++;
682           else if ((*i)->getPath()->size() == 0)
683             count++;
684         }
685     }
686   return count;
687 }
688 
689 // End of file
690