initial commit, lordsawar source, slightly modified
[lordsawar] / src / AI_Allocation.cpp
1 // Copyright (C) 2004 John Farrell
2 // Copyright (C) 2004, 2005, 2006, 2007 Ulf Lorenz
3 // Copyright (C) 2008, 2009 Ben Asselstine
4 //
5 //  This program is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Library General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
18 //  02110-1301, USA.
19
20 #include <iostream>
21 #include <assert.h>
22 #include "AI_Analysis.h"
23 #include "AI_Allocation.h"
24 #include "player.h"
25 #include "playerlist.h"
26 #include "citylist.h"
27 #include "stacklist.h"
28 #include "stack.h"
29 #include "city.h"
30 #include "Threat.h"
31 #include "MoveResult.h"
32 #include "ruin.h"
33 #include "path.h"
34 #include "ruinlist.h"
35 #include "GameMap.h"
36 #include "GameScenarioOptions.h"
37 #include "Threatlist.h"
38 #include "PathCalculator.h"
39 #include "stacktile.h"
40 #include "stackreflist.h"
41 #include "armyproto.h"
42 #include "QuestsManager.h"
43 #include "Quest.h"
44 #include "QKillHero.h"
45 #include "QEnemyArmies.h"
46 #include "QEnemyArmytype.h"
47
48 using namespace std;
49
50 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<flush<<endl;}
51 //#define debug(x)
52
53 AI_Allocation* AI_Allocation::s_instance = 0;
54
55
56 AI_Allocation::AI_Allocation(AI_Analysis *analysis, const Threatlist *threats, Player *owner)
57     :d_owner(owner), d_analysis(analysis), d_threats(threats)
58 {
59     s_instance = this;
60 }
61
62 AI_Allocation::~AI_Allocation()
63 {
64     s_instance = 0;
65 }
66
67 StackReflist::iterator AI_Allocation::eraseStack(StackReflist::iterator it)
68 {
69   setParked(*it, true);
70   return d_stacks->eraseStack(it);
71 }
72 void AI_Allocation::deleteStack(Stack* s)
73 {
74   //this method deletes it from our list of stacks to consider.
75   //it doesn't really delete the stack from the game.
76     // we need to remove collaterally eradicated stacks before they make
77     // trouble
78     if (s_instance)
79       {
80         s_instance->setParked(s, true);
81         s_instance->d_stacks->removeStack(s->getId());
82       }
83 }
84
85 int AI_Allocation::allocateStackToCapacityBuilding(Threat *threat, City *first_city, bool take_neutrals)
86 {
87   bool moved = false;
88   Vector<int> pos;
89   if (first_city)
90     pos = threat->getClosestPoint(first_city->getPos());
91   else if (d_owner->getStacklist()->size() > 0)
92     pos = threat->getClosestPoint(d_owner->getStacklist()->front()->getPos());
93   else
94     return moved;
95   City *c =GameMap::getEnemyCity(pos);
96   if (!c)
97     return moved;
98   if (c->isBurnt() == true)
99     return moved;
100   if (c->getOwner() == Playerlist::getInstance()->getNeutral() && take_neutrals == false)
101     return moved;
102   Stack *attacker = findClosestStackToEnemyCity(c, take_neutrals);
103   if (!attacker)
104     return moved;
105   Vector<int> dest = threat->getClosestPoint(attacker->getPos());
106   bool killed = false;
107   //only take what we need.
108   std::list<guint32> armies = attacker->determineStrongArmies(3.0);
109   if (armies.size() > 0 && armies.size() != attacker->size())
110     {
111       Stack *stack = d_owner->stackSplitArmies(attacker, armies);
112       moved = moveStack(stack, dest, killed);
113       if (!killed)
114         {
115           if (stack->hasPath() == false)
116             d_stacks->addStack(stack);
117         }
118     }
119   else
120     {
121       moved = moveStack(attacker, dest, killed);
122       if (!killed)
123         {
124           if (attacker->hasPath() == true)
125             deleteStack(attacker);
126         }
127     }
128   return moved;
129 }
130
131 int AI_Allocation::allocateStacksToCapacityBuilding(City *first_city,
132                                                     bool take_neutrals)
133 {
134   int count = 0;
135
136   for (Threatlist::const_iterator it = d_threats->begin(); 
137        it != d_threats->end(); it++)
138     {
139       Threat *t = *it;
140       if (d_stacks->size() == 0)
141         break;
142       if (t->isCity() && t->getStrength() <= 0.5003)
143         {
144           if (allocateStackToCapacityBuilding(*it, first_city, take_neutrals))
145             {
146               count++;
147             }
148         }
149     }
150   return count;
151 }
152
153 bool AI_Allocation::continueQuest(Quest *quest, Stack *stack)
154 {
155   Vector<int> dest = d_owner->AI_getQuestDestination(quest, stack);
156   if (dest == Vector<int>(-1,-1))
157     return false;
158   bool killed = false;
159   bool moved = moveStack(stack, dest, killed);
160   if (!killed)
161     {
162       groupStacks(stack);
163       deleteStack(stack);
164     }
165   return moved;
166 }
167
168 int AI_Allocation::continueQuests()
169 {
170   int count = 0;
171   if (GameScenarioOptions::s_play_with_quests == GameParameters::NO_QUESTING)
172     return count;
173
174   std::vector<Quest*> quest = 
175     QuestsManager::getInstance()->getPlayerQuests(d_owner);
176   for (std::vector<Quest*>::iterator i = quest.begin(); i != quest.end(); i++)
177     {
178       Quest *quest = *i;
179       if (quest->isPendingDeletion())
180         continue;
181       Stack *s = d_owner->getStacklist()->getArmyStackById(quest->getHeroId());
182       bool moved = continueQuest(quest, s);
183       if (moved)
184         count++;
185     }
186   return count;
187 }
188
189 int AI_Allocation::continueAttacks()
190 {
191   int count = 0;
192   for (StackReflist::iterator i = d_stacks->begin(); i != d_stacks->end(); i++)
193     {
194       Stack *s = *i;
195       if (s->getParked() == false && s->isOnCity() == false &&
196           s->hasPath() == true && 
197           GameMap::getEnemyCity(s->getLastPointInPath()) != NULL)
198         {
199           bool killed = false;
200           bool moved = moveStack(s, killed);
201           if (moved)
202             count++;
203           if (!killed)
204             {
205               if (s->hasPath() == true)
206                 {
207                   i = eraseStack(i);
208                 }
209               else
210                 {
211                   if (s->isOnCity() == true)
212                     shuffleStacksWithinCity(GameMap::getCity(s), s,
213                                             Vector<int>(0,0));
214                   i = eraseStack(i);
215                 }
216             }
217         }
218     }
219   return count;
220 }
221
222 int AI_Allocation::attackNearbyEnemies()
223 {
224   int count = 0;
225   Citylist *cl = Citylist::getInstance();
226   for (Citylist::iterator i = cl->begin(); i != cl->end(); i++)
227     {
228       sbusy.emit();
229       if (d_owner->abortRequested())
230         return count;
231       if (d_stacks->size() == 0)
232         break;
233       City *city = *i;
234       if (city->getOwner() == d_owner || city->isBurnt() == true)
235         continue;
236       std::list<Vector<int> > p = GameMap::getNearbyPoints(city->getPos(), 2);
237       for (std::list<Vector<int> >::iterator j = p.begin(); j != p.end(); j++)
238         {
239           Stack *s = GameMap::getFriendlyStack(*j);
240           if (!s)
241             continue;
242           if (s->getParked() == false && s->getMoves() >= 4)
243             {
244               bool killed = false;
245               bool moved;
246               moved = moveStack(s, city->getNearestPos(s->getPos()), killed);
247               if (!killed)
248                 {
249                   if (s->hasPath() == true)
250                     deleteStack(s);
251                   else if (s->isOnCity() == true)
252                     {
253                       deleteStack(s);
254                       shuffleStacksWithinCity(GameMap::getCity(s), s, 
255                                               Vector<int>(0,0));
256                     }
257                 }
258               else
259                 break;
260               if (moved)
261                 count++;
262             }
263           //break;
264         }
265     }
266   //return count;
267   Stacklist *sl = d_owner->getStacklist();
268   std::list<Vector<int> > pos = sl->getPositions();
269   for (std::list<Vector<int> >::iterator i = pos.begin(); i != pos.end(); i++)
270     {
271       sbusy.emit();
272       if (d_owner->abortRequested())
273         return count;
274       Stack *s = GameMap::getFriendlyStack(*i);
275       if (!s)
276         continue;
277       if (d_stacks->size() == 0)
278         break;
279       if (s->isOnCity() == true)
280         continue;
281       if (s->getParked() == true)
282         continue;
283       std::list<Vector<int> > p = GameMap::getNearbyPoints(*i, 2);
284       for (std::list<Vector<int> >::iterator j = p.begin(); j != p.end(); j++)
285         {
286           Stack *enemy = GameMap::getEnemyStack(*j);
287           if (!enemy)
288             continue;
289           bool killed = false;
290           bool moved;
291           if (enemy->isOnCity() == true)
292             continue;
293           if (s->size() < enemy->size())
294             continue;
295           if (s->hasShip() != enemy->hasShip())
296             continue;
297           moved = moveStack(s, enemy->getPos(), killed);
298           if (moved)
299             count++;
300           if (!killed)
301             {
302               if (s->hasPath() == true)
303                 deleteStack(s);
304             }
305           else
306             break;
307         }
308     }
309   return count;
310 }
311
312 bool AI_Allocation::emptyOutCities()
313 {
314   //everybody out on the dancefloor.
315   Citylist *cl = Citylist::getInstance();
316   for (Citylist::iterator it = cl->begin(); it != cl->end(); it++)
317     {
318       
319       sbusy.emit();
320       if (d_owner->abortRequested())
321         return false;
322       City *c = *it;
323       if (c->getOwner() != d_owner || c->isBurnt() == true)
324         continue;
325       bool bail = false;
326       guint32 num_defenders = c->countDefenders();
327       for (guint i = 0; i < c->getSize(); i++)
328         {
329           for (guint j = 0; j < c->getSize(); j++)
330             {
331               Stack *s = GameMap::getStack(c->getPos() + Vector<int>(i,j));
332               if (!s)
333                 continue;
334               if ((s->getMoves() > 3 && s->size() >= 4 &&
335                    (num_defenders - s->size()) >= 3) || (rand() % 10) == 0)
336                 {
337                   City *target = cl->getNearestEnemyCity(s->getPos());
338                   if (target)
339                     {
340                       bool killed = false;
341                       if (d_stacks->contains(s->getId()) == false)
342                         d_stacks->addStack(s);
343                       moveStack(s, target->getNearestPos(s->getPos()), killed);
344                     }
345                   else
346                     return false;
347                   bail = true;
348                   break;
349                 }
350             }
351           if (d_owner->getGold() < 20)
352             continue;
353           if (bail)
354             break;
355         }
356     }
357   return true;
358 }
359
360 int AI_Allocation::visitTemples(bool get_quests)
361 {
362   int count = 0;
363   Stacklist *sl = d_owner->getStacklist();
364   std::list<Vector<int> > pos = sl->getPositions();
365   for (std::list<Vector<int> >::iterator i = pos.begin(); i != pos.end(); i++)
366     {
367       Stack *s = GameMap::getFriendlyStack(*i);
368       if (!s)
369         continue;
370       if (s->isOnCity() == true)
371         continue;
372       if (s->hasHero() && get_quests)
373         {
374           bool moved;
375           bool killed = false;
376           moved = d_owner->AI_maybeVisitTempleForQuest(s, s->getMoves(), 
377                                                        s->getMoves() + 17,
378                                                        killed);
379           if (moved)
380             count++;
381           //if (!killed && moved && s->hasPath() == true)
382             //deleteStack(s);
383         }
384       else
385         {
386           bool moved;
387           bool killed = false;
388           bool blessed = false;
389           moved = d_owner->AI_maybeVisitTempleForBlessing(s, s->getMoves(), 
390                                                        s->getMoves() + 7, 
391                                                        50.0, blessed, killed);
392           if (moved)
393             count++;
394           //if (!killed && moved && s->hasPath() == true)
395             //deleteStack(s);
396         }
397     }
398   return count;
399 }
400
401 int AI_Allocation::visitRuins()
402 {
403   int count = 0;
404   Stacklist *sl = d_owner->getStacklist();
405   std::list<Vector<int> > pos = sl->getPositions();
406   for (std::list<Vector<int> >::iterator i = pos.begin(); i != pos.end(); i++)
407     {
408       Stack *s = GameMap::getFriendlyStack(*i);
409       if (!s)
410         continue;
411       if (s->isOnCity() == true)
412         continue;
413       if (s->hasHero())
414         {
415           bool moved;
416           bool killed = false;
417           moved = d_owner->AI_maybeVisitRuin(s, s->getMoves(), 
418                                              s->getMoves() + 17, killed);
419           if (moved)
420             count++;
421           //if (!killed && moved && s->hasPath() == true)
422             //deleteStack(s);
423         }
424     }
425   return count;
426 }
427
428 int AI_Allocation::pickupItems()
429 {
430   int count = 0;
431   if (d_owner->getHeroes().size() == 0)
432     return count;
433   std::vector<Vector<int> > items = GameMap::getInstance()->getItems();
434   for (std::vector<Vector<int> >::iterator i = items.begin(); i != items.end();
435        i++)
436     {
437       std::list<Stack*> s = GameMap::getNearbyFriendlyStacks(*i, 8);
438       for (std::list<Stack*>::iterator j = s.begin(); j != s.end(); j++)
439         {
440           Stack *s = *j;
441           if (s->hasHero() == false)
442             continue;
443           if (GameMap::getEnemyCity(*i) != NULL)
444             continue;
445           if (s->isOnCity() == false)
446             {
447               bool killed = false;
448               if (moveStack(s, *i, killed))
449                 {
450                   count++;
451                   if (!killed)
452                     {
453                       if (s->getPos() == *i)
454                         {
455                           Hero *hero = dynamic_cast<Hero*>(s->getFirstHero());
456                           d_owner->heroPickupAllItems (hero, *i);
457                         }
458                       //deleteStack(s);
459                     }
460                 }
461             }
462           else
463             {
464               City *c = GameMap::getCity(s->getPos());
465               if (c->contains(*i) == true)
466                 {
467                   bool killed = false;
468                   if (moveStack(s, *i, killed))
469                     {
470                       count++;
471                       if (!killed)
472                         {
473                           if (s->getPos() == *i)
474                             {
475                               Hero *hero = dynamic_cast<Hero*>(s->getFirstHero());
476                               d_owner->heroPickupAllItems (hero, *i);
477                             }
478                           deleteStack(s);
479                         }
480                     }
481                 }
482             }
483           break;
484         }
485     }
486   return count;
487 }
488
489 int AI_Allocation::move(City *first_city, bool take_neutrals)
490 {
491   int temple_moved = 0, ruin_moved = 0, pickup_moved = 0, attack_moved = 0, quest_moved = 0, immediate_moved = 0, defensive_moved = 0, capacity_moved = 0, offensive_moved = 0, default_moved= 0;
492   int temple_alloc = 0, ruin_alloc = 0, pickup_alloc = 0, attack_alloc = 0, quest_alloc = 0, immediate_alloc = 0, defensive_alloc = 0, capacity_alloc = 0, offensive_alloc = 0, default_alloc= 0;
493   int moved;
494   // move stacks
495   d_stacks = new StackReflist(d_owner->getStacklist(), true);
496
497   int total = d_stacks->size();
498   debug("Player " << d_owner->getName() << " starts with " << d_stacks->size() << " stacks to do something with");
499
500   int count = 0;
501
502   sbusy.emit();
503   if (d_owner->abortRequested())
504     return count;
505
506   // go on a quest
507   quest_alloc = d_stacks->size();
508   moved = continueQuests();
509   quest_moved = moved;
510   quest_alloc -= d_stacks->size();
511   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to fulfilling quests");
512   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in quest mode.");
513
514   sbusy.emit();
515   if (d_owner->abortRequested())
516     return count;
517   //move stacks to temples for blessing, or ones with heroes for a quest.
518   temple_alloc = d_stacks->size();
519   moved = visitTemples(GameScenarioOptions::s_play_with_quests != GameParameters::NO_QUESTING);
520   temple_moved = moved;
521   temple_alloc -= d_stacks->size();
522   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to visiting temples");
523   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in temple-visiting mode.");
524
525   sbusy.emit();
526   if (d_owner->abortRequested())
527     return count;
528   //move hero stacks to ruins for searching.
529   ruin_alloc = d_stacks->size();
530   moved = visitRuins();
531   ruin_moved = moved;
532   ruin_alloc -= d_stacks->size();
533   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to visiting ruins");
534   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in ruin-visiting mode.");
535
536   sbusy.emit();
537   if (d_owner->abortRequested())
538     return count;
539   //if we're near a bag of stuff, go pick it up.
540   pickup_alloc = d_stacks->size();
541   moved = pickupItems();
542   pickup_moved = moved;
543   pickup_alloc -= d_stacks->size();
544   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to picking up items");
545   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in pickup-items mode.");
546
547   sbusy.emit();
548   if (d_owner->abortRequested())
549     return count;
550   // if a stack has a path for an enemy city and is outside of a city, then keep going.
551   attack_alloc = d_stacks->size();
552   moved = continueAttacks();
553   attack_moved = moved;
554   attack_alloc -= d_stacks->size();
555   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to continuing attacks");
556   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in continuing-attacks mode.");
557
558   sbusy.emit();
559   if (d_owner->abortRequested())
560     return count;
561   // if a stack is 2 tiles away from another enemy city, then attack it.
562   immediate_alloc = d_stacks->size();
563   moved = attackNearbyEnemies();
564   immediate_moved = moved;
565   immediate_alloc -= d_stacks->size();
566   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to attacking nearby stacks");
567   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in attack-nearby-stacks mode.");
568
569   sbusy.emit();
570   if (d_owner->abortRequested())
571     return count;
572   //if (take_neutrals)
573     {
574       capacity_alloc = d_stacks->size();
575       moved = allocateStacksToCapacityBuilding(first_city, take_neutrals);
576       capacity_moved = moved;
577       capacity_alloc -= d_stacks->size();
578       debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to capacity building");
579       debug("Player " << d_owner->getName() << " moved " << moved << " stacks in capacity building mode.");
580       count+=moved;
581     }
582   //printf("here1\n");
583   checkAmbiguities();
584
585   sbusy.emit();
586   if (d_owner->abortRequested())
587     return count;
588   defensive_alloc = d_stacks->size();
589   moved = allocateDefensiveStacks(Citylist::getInstance());
590   defensive_moved = moved;
591   defensive_alloc -= d_stacks->size();
592   count +=moved;
593   debug("Player " << d_owner->getName() << " has " << d_stacks->size() << " stacks after assigning defenders");
594   debug("Player " << d_owner->getName() << " moved " << count << " stacks in defensive mode.");
595
596   //printf("here2\n");
597   checkAmbiguities();
598   if (d_stacks->size() == 0)
599     {
600       delete d_stacks;
601       return count;
602     }
603
604   sbusy.emit();
605   if (d_owner->abortRequested())
606     return count;
607   offensive_alloc = d_stacks->size();
608   moved = allocateStacksToThreats();
609   offensive_moved = moved;
610   offensive_alloc -= d_stacks->size();
611   count+= moved;
612   debug("Player " << d_owner->getName() << " still has " << d_stacks->size() << " stacks after allocating stacks to threats")
613     debug("Player " << d_owner->getName() << " moved " << moved << " stacks in offensive mode.");
614
615  //printf("here3\n");
616   checkAmbiguities();
617   if (d_stacks->size() == 0)
618     {
619       delete d_stacks;
620       return count;
621     }
622       
623   sbusy.emit();
624   if (d_owner->abortRequested())
625     return count;
626   default_alloc = d_stacks->size();
627   moved = defaultStackMovements();
628   default_moved = moved;
629   default_alloc -= d_stacks->size();
630   debug("Player " << d_owner->getName() << " moved " << moved << " stacks in Default stack movements.");
631   count+= moved;
632
633   sbusy.emit();
634   if (d_owner->abortRequested())
635     return count;
636   //empty out the cities damnit.
637   emptyOutCities();
638   //printf("here4\n");
639   checkAmbiguities();
640   debug("Player " << d_owner->getName() << " moved totals: " << attack_moved << "," << capacity_moved <<"," <<defensive_moved<<"," << offensive_moved <<"," << default_moved <<".");
641   debug("Player " << d_owner->getName() << " alloc totals: " << attack_alloc << "," << capacity_alloc <<"," <<defensive_alloc<<"," << offensive_alloc <<"," << default_alloc <<" (" << total <<").");
642   delete d_stacks;
643
644   //if (IIId_owner->getId() == 0)
645     //exit(0);
646   return count;
647 }
648
649 int AI_Allocation::allocateDefensiveStacksToCity(City *city)
650 {
651   int count = 0;
652   float cityDanger = d_analysis->getCityDanger(city);
653   //if city is not endangered, we keep a skeleton crew.
654   //if a city has 10 strength in it, it's probably pretty safe.
655   if (cityDanger < 3.0) 
656     cityDanger = 3.0;
657   else if (cityDanger > 10.0)
658     cityDanger = 10.0;
659
660   // Look how many defenders the city already has
661   float totalDefenderStrength = 0.0;
662   for (guint32 i = 0; i < city->getSize(); i++)
663     for (guint32 j = 0; j < city->getSize(); j++)
664       {
665         Stack *d = GameMap::getFriendlyStack(city->getPos() + Vector<int>(i,j));
666         if (d && d->getParked() == false)
667           shuffleStacksWithinCity(city, d, Vector<int>(0,0));
668       }
669   std::vector<Stack*> defenders = city->getDefenders();
670   vector<Stack*>::iterator it;
671   for (it = defenders.begin(); it != defenders.end(); it++)
672     {
673       Stack *defender = *it;
674       if (defender->getParked() == true)
675         continue;
676       //shuffleStacksWithinCity(city, defender, Vector<int>(0,0));
677       float stackStrength = d_analysis->assessStackStrength(defender);
678       debug("Player " << d_owner->getName() << " assigns some or all of stack " << defender->getId() << " with strength " << stackStrength
679             << " to " << city->getName() << " because its danger is " << cityDanger)
680
681         totalDefenderStrength += stackStrength;
682       if (totalDefenderStrength > cityDanger)
683         {
684           float diff = totalDefenderStrength - cityDanger;
685           //we need to excise DIFF points from this stack.
686           std::list<guint32> armies = (*it)->determineWeakArmies(diff);
687           //split off some armies in this stack.
688           if (armies.size() > 0 && armies.size() != defender->size())
689             {
690               Vector<int> dest = getFreeOtherSpotInCity(city, defender);
691               if (dest != Vector<int>(-1,-1))
692                 {
693                   Stack *stack = d_owner->stackSplitArmies(defender, 
694                                                            armies);
695                   if (stack->getMoves() > 0)
696                     {
697                       if (shuffleStack(stack, dest, false))
698                         {
699                           count++;
700                           if (stack->getParked() == false)
701                             d_stacks->addStack(stack);
702                         }
703                     }
704                   else
705                     groupStacks(defender);
706                 }
707             }
708
709           deleteStack(defender);
710           break;
711         }
712       else
713         {
714           deleteStack(defender);
715         }
716       // if we get here, we have assigned defenders but not enough to
717       // counter the danger that the city is in
718     }
719
720   // allocate nearby stacks to come back to the city,
721   // because we don't have enough defence
722   // this is disabled for now.
723   while (totalDefenderStrength < cityDanger )
724     {
725       break;
726       Stack *s = findClosestStackToCity(city);
727       if (!s) 
728         {
729           debug("City " << city->getName() << " is endangered but no stacks are close enough to go defend it (or no more space available in city).")
730             break;
731         }
732       debug("Stack " << s->getId() << " at " << s->getPos().x << "," << s->getPos().y << " should return to " << city->getName() << " to defend")
733         Vector<int> dest = getFreeSpotInCity(city, s->size());
734       if (dest == Vector<int>(-1,-1))
735         break;
736       float stackStrength = d_analysis->assessStackStrength(s);
737       totalDefenderStrength += stackStrength;
738
739       if (totalDefenderStrength > cityDanger)
740         {
741           float diff = totalDefenderStrength - cityDanger;
742           //we need to excise DIFF points from this stack.
743           std::list<guint32> armies = s->determineWeakArmies(diff);
744           //split off some armies in this stack.
745           if (armies.size() > 0 && armies.size() != s->size())
746             {
747               Stack *stack = d_owner->stackSplitArmies(s, armies);
748               d_stacks->addStack(stack);
749             }
750
751         }
752       deleteStack(s);
753
754       bool killed = false;
755       if (moveStack(s, dest, killed))
756         {
757           count++;
758         }
759     }
760
761   if (totalDefenderStrength < cityDanger)
762     {
763       debug(city->getName() << " cannot be adequately defended")
764     }
765   return count;
766 }
767
768 // for each city, if it is in danger at all, allocate a stack to be its
769 // defender. These stacks sit in the NW corner and don't move out of the city.
770 int AI_Allocation::allocateDefensiveStacks(Citylist *cities)
771 {
772   //we need to split the stacks and add the newly split ones to d_stacks.
773   int count = 0;
774   for (Citylist::iterator it = cities->begin(); it != cities->end(); ++it)
775     {
776       City *city = (*it);
777       if (!city->isFriend(d_owner) || city->isBurnt())
778         continue;
779       count += allocateDefensiveStacksToCity(city);
780       sbusy.emit();
781       if (d_owner->abortRequested())
782         return count;
783
784     }
785   return count;
786 }
787
788 int AI_Allocation::allocateStacksToThreat(Threat *threat)
789 {
790   int count = 0;
791   float threat_danger = threat->getDanger() * 1.000;
792   if (threat_danger > 32.0) //e.g. 32 light infantry in a city.
793     threat_danger = 32.0;
794   City *city = GameMap::getCity(threat->getClosestPoint(Vector<int>(0,0)));
795   while (true)
796     {
797       if (city && city->getOwner() == d_owner)
798         break;
799       guint32 num_city_defenders = 0;
800       Stack *attacker = findBestAttackerFor(threat, num_city_defenders);
801       //if (attacker && attacker->getId() == 4207)
802         //{
803           //printf("4207 was chosen for threat: `%s'\n", threat->toString().c_str());
804         //}
805       // if there is nobody to attack the threat, go onto the next one
806       if (!attacker) 
807         break;
808       float score = d_analysis->assessStackStrength(attacker);
809       bool killed = false;
810       Vector<int> dest = threat->getClosestPoint(attacker->getPos());
811       //if (attacker->getId() == 4207)
812         //{
813           //printf("dest is %d,%d\n", dest.x, dest.y);
814           //exit(0);
815         //}
816       if (num_city_defenders == 0 || num_city_defenders - attacker->size() > 3)
817         {
818
819         debug("Player " << d_owner->getName() << " thinking about attacking threat at (" << dest.x <<"," << dest.y << ") with stack " << attacker->getId() <<" at ("<<attacker->getPos().x<<","<<attacker->getPos().y<<")");
820         deleteStack(attacker);
821           if (moveStack(attacker, dest, killed))
822             {
823               count++;
824               if (!killed)
825                 {
826                   if (attacker->isOnCity())
827                     {
828                       shuffleStacksWithinCity (GameMap::getCity(attacker), 
829                                                attacker, Vector<int>(0,0));
830                       //setParked(attacker, true);
831
832                     }
833                 }
834             }
835         }
836       else
837         {
838           std::list<guint32> armies = attacker->determineStrongArmies(3.0);
839           if (armies.size() > 0 && armies.size() != attacker->size())
840             {
841               Stack *stack = d_owner->stackSplitArmies(attacker, armies);
842               score = d_analysis->assessStackStrength(stack);
843               debug("Player " << d_owner->getName() << " thinking about attacking threat at (" << dest.x <<"," << dest.y << ") with split stack " << stack->getId() <<" at ("<<stack->getPos().x<<","<<stack->getPos().y<<")");
844               bool moved = moveStack(stack, dest, killed);
845               if (!killed)
846                 {
847                   if (stack->hasPath() == false)
848                     d_stacks->addStack(stack);
849                 }
850               if (moved)
851                 count++;
852             }
853         }
854
855       threat_danger -= score;
856       // if the threat has been removed, go onto the next one
857       if (threat->getStrength() == 0.0)
858         break;
859       if (threat_danger <= 0)
860         break;
861     }
862   return count;
863 }
864
865 int AI_Allocation::allocateStacksToThreats()
866 {
867   int count = 0;
868
869   for (Threatlist::const_iterator it = d_threats->begin(); 
870        it != d_threats->end(); ++it)
871     {
872       if ((*it)->isCity())
873         count += allocateStacksToThreat(*it);
874
875       if (d_stacks->size() == 0)
876         break;
877       sbusy.emit();
878       if (d_owner->abortRequested())
879         return count;
880
881     }
882   return count;
883 }
884
885 Vector<int> AI_Allocation::getFreeOtherSpotInCity(City *city, Stack *stack)
886 {
887   guint size = 0;
888   Vector<int> best = Vector<int>(-1,-1);
889   assert (city->contains(stack->getPos()) == true);
890   for (unsigned int i = 0; i < city->getSize(); i++)
891     for (unsigned int j = 0; j < city->getSize(); j++)
892       {
893         Vector<int> pos = city->getPos() + Vector<int>(i,j);
894         if (pos == stack->getPos())
895           continue;
896         if (GameMap::canAddArmies(pos, stack->size()) == false)
897           continue;
898         std::list<Stack*> f = GameMap::getFriendlyStacks(pos);
899         if (f.size() > 0)
900           {
901             for (std::list<Stack*>::iterator i = f.begin(); i != f.end(); i++)
902               {
903                 if ((*i)->size() > size)
904                   {
905                     size = (*i)->size();
906                     best = pos;
907                   }
908               }
909           }
910         else
911           {
912             if (size == 0)
913               best = pos;
914           }
915       }
916   return best;
917 }
918 Vector<int> AI_Allocation::getFreeSpotInCity(City *city, int stackSize)
919 {
920   for (unsigned int i = 0; i < city->getSize(); i++)
921     for (unsigned int j = 0; j < city->getSize(); j++)
922       {
923         Vector<int> pos = city->getPos() + Vector<int>(i,j);
924         if (GameMap::canAddArmies(pos, stackSize) == false)
925           continue;
926         return pos;
927       }
928   //there's no room in the inn.
929   return Vector<int>(-1,-1);
930 }
931
932 Stack *AI_Allocation::findClosestStackToEnemyCity(City *city, bool try_harder)
933 {
934   Vector<int> pos = city->getPos();
935   Stack *best = 0;
936   int lowest_mp = -1;
937   for (StackReflist::iterator it = d_stacks->begin(); it != d_stacks->end(); ++it)
938     {
939       Stack* s = *it;
940       if (s->getParked() == true)
941         continue;
942
943       int tiles = dist(city->getPos(), s->getPos());
944       if (tiles > 51)
945         continue;
946       int moves = (tiles + 6) / 7;
947
948       if (try_harder == false && s->isOnCity())
949         {
950           City *source_city = GameMap::getCity(s);
951           if (source_city)
952             {
953               if (d_analysis->getNumberOfDefendersInCity(source_city) <= 
954                   (3 + 4))
955                 continue;
956             }
957         }
958
959       if (moves < lowest_mp || lowest_mp == -1)
960         {
961           best = s;
962           lowest_mp = moves;
963         }
964     }
965   return best;
966 }
967
968 Stack *AI_Allocation::findClosestStackToCity(City *city)
969 {
970   Vector<int> pos = city->getPos();
971   Stack *best = 0;
972   int lowest_mp = -1;
973   for (StackReflist::iterator it = d_stacks->begin(); it != d_stacks->end(); ++it)
974     {
975       Stack* s = *it;
976       if (s->getParked() == true)
977         continue;
978       //don't consider the stack if it's already in the city
979       Vector<int> spos = s->getPos();
980       if (city->contains(spos))
981         continue;
982       //don't consider the city if we can't fit this stack anywhere inside it.
983       Vector<int> dest = getFreeSpotInCity(city, s->size());
984       if (dest == Vector<int>(-1, -1))
985         continue;
986       //don't consider the stack if it's in an endangered city
987       City *source_city = GameMap::getCity(s);
988       if (source_city)
989         {
990           if (d_analysis->getNumberOfDefendersInCity(source_city) <= 3)
991             continue;
992         }
993
994       int tiles = dist(city->getPos(), s->getPos());
995       int moves = (tiles + 6) / 7;
996       if (moves < lowest_mp || lowest_mp == -1)
997         {
998           best = s;
999           lowest_mp = moves;
1000         }
1001     }
1002   return best;
1003 }
1004
1005 Stack *AI_Allocation::findBestAttackerFor(Threat *threat, guint32 &city_defenders)
1006 {
1007   Stack *best = NULL;
1008   float best_score = -1.0;
1009   for (StackReflist::iterator it = d_stacks->begin(); it != d_stacks->end(); ++it)
1010     {
1011       Stack* s = *it;
1012       if (s->getParked() == true)
1013         continue;
1014       Vector<int> closestPoint = threat->getClosestPoint(s->getPos());
1015       // threat has been destroyed anyway
1016       if (closestPoint.x == -1)
1017         return 0;
1018       Vector<int> spos = s->getPos();
1019
1020       int distToThreat = dist(closestPoint, spos);
1021       if (distToThreat > 27)
1022         continue;
1023       else if (distToThreat == 0)
1024         continue;
1025
1026       //don't consider the stack if it's in an endangered city
1027       City *source_city = GameMap::getCity(s);
1028       guint32 num_source_city_defenders = 0;
1029       if (source_city)
1030         {
1031           num_source_city_defenders = 
1032             d_analysis->getNumberOfDefendersInCity(source_city);
1033           if (num_source_city_defenders <= (3 + 4))
1034             continue;
1035         }
1036
1037       int score = d_analysis->assessStackStrength(s);
1038       if (score > best_score || best_score == -1.0)
1039         {
1040           best = s;
1041           best_score = score;
1042           city_defenders = num_source_city_defenders;
1043         }
1044     }
1045   return best;
1046 }
1047
1048 int AI_Allocation::defaultStackMovements()
1049 {
1050   int count = 0;
1051   Citylist *allCities = Citylist::getInstance();
1052   debug("Default movement for " <<d_stacks->size() <<" stacks");
1053
1054   while (d_stacks->size() > 0)
1055     {
1056       sbusy.emit();
1057       if (d_owner->abortRequested())
1058         return count;
1059       Stack* s = d_stacks->front();
1060       debug("Player " << d_owner->getName() << " thinking about default movements for stack " << s->getId() <<" at ("<<s->getPos().x<<","<<s->getPos().y<<")");
1061       deleteStack(s);
1062       bool leave = false;
1063
1064       City *source_city = GameMap::getCity(s);
1065       if (source_city)
1066         {
1067           if (s->isFull() &&
1068               source_city->countDefenders() - s->isFull() > 3)
1069             leave = true;
1070         }
1071       else
1072         leave = true;
1073
1074       if (leave == true)
1075         {
1076           bool moved = false;
1077           City* enemyCity = allCities->getNearestEnemyCity(s->getPos());
1078           if (enemyCity)
1079             {
1080               int mp = s->getPath()->calculate(s, enemyCity->getNearestPos(s->getPos()));
1081               debug("Player " << d_owner->getName() << " attacking " <<enemyCity->getName() << " that is " << mp << " movement points away");
1082               if (mp > 0)
1083                 {
1084                   bool killed = false;
1085                   moved = moveStack(s, killed);
1086                   if (!killed)
1087                     {
1088                       if (s->isOnCity())
1089                         shuffleStacksWithinCity (GameMap::getCity(s), s, 
1090                                                  Vector<int>(0,0));
1091                       //setParked(s, true);
1092                     }
1093                   if (moved)
1094                     count++;
1095                 }
1096             }
1097           else
1098             {
1099               enemyCity = allCities->getNearestForeignCity(s->getPos());
1100               if (enemyCity)
1101                 {
1102                   s->getOwner()->proposeDiplomacy(Player::PROPOSE_WAR,
1103                                                   enemyCity->getOwner());
1104                   debug("Player " << d_owner->getName() << " attacking " <<enemyCity->getName())
1105                     int mp = s->getPath()->calculate(s, enemyCity->getNearestPos(s->getPos()));
1106                   if (mp > 0)
1107                     {
1108                       bool killed = false;
1109                       moved = moveStack(s, killed);
1110                       if (!killed)
1111                         {
1112                           if (s->isOnCity())
1113                             shuffleStacksWithinCity (GameMap::getCity(s), 
1114                                                      s, Vector<int>(0,0));
1115                           //setParked(s, true);
1116                         }
1117                       if (moved)
1118                         count++;
1119                     }
1120                 }
1121             }
1122
1123           if (!moved)
1124             {
1125               // for some reason (islands are one bet), we could not attack the
1126               // enemy city. Let's iterator through all cities and attack the first
1127               // one we can lay our hands on.
1128               debug("Mmmh, did not work.")
1129                 //sleep (10);
1130                 /*
1131                    MoveResult *result = 0;
1132                    for (Citylist::iterator cit = allCities->begin(); cit != allCities->end(); cit++)
1133                    if ((*cit)->getOwner() != d_owner)
1134                    {
1135                    debug("Let's try "<<(*cit).getName() <<" instead.")
1136                    result = moveStack(s, (*cit)->getPos());
1137                    if (result && result->moveSucceeded())
1138                    {
1139                    debug("Worked")
1140                    count++;
1141                    break;
1142                    }
1143                    }
1144                  */
1145             }
1146         }
1147       else
1148         {
1149           bool moved;
1150           if (!source_city)
1151             {
1152               //moved = stackReinforce(s);
1153               continue;
1154             }
1155           else
1156             {
1157               City *c = source_city;
1158               debug("stack " << s->getId() <<" at ("<<s->getPos().x<<","<<s->getPos().y<<") shuffling in city " << c->getName());
1159               moved = shuffleStacksWithinCity (c, s, Vector<int>(0,0));
1160               //setParked(s, true);  valgrind doesn't like this.
1161             }
1162
1163           if (moved)
1164             count++;
1165         }
1166     }
1167   return count;
1168 }
1169
1170 bool AI_Allocation::stackReinforce(Stack *s)
1171 {
1172   Citylist *allCities = Citylist::getInstance();
1173   float mostNeeded = -1000.0;
1174   City *cityNeeds = 0;
1175   int moves = 1000;
1176   Vector<int> target_tile = Vector<int>(-1,-1);
1177   for (Citylist::iterator it = allCities->begin(); it != allCities->end(); ++it)
1178     {
1179       City *city = (*it);
1180       if (city->getOwner() != d_owner)
1181         continue;
1182       if (city->isBurnt() == true)
1183         continue;
1184       int distToCity = dist(s->getPos(), city->getPos());
1185
1186       //if the city already contains the given stack, then disregard it
1187       //hopefully it will be shuffled later
1188       if (city->contains(s->getPos()))
1189         return false;
1190
1191       //disregard if the city is too far away
1192       int movesToCity = (distToCity + 6) / 7;
1193       if (movesToCity > 3) continue;
1194       
1195       //disregard if the city can't hold our stack
1196       Vector<int> dest = getFreeSpotInCity(city, s->size());
1197       if (dest == Vector<int>(-1,-1))
1198         continue;
1199
1200       //pick the city that needs us the most
1201       float need = d_analysis->reinforcementsNeeded(city);
1202       if (need > mostNeeded)
1203         {
1204           cityNeeds = city;
1205           mostNeeded = need;
1206           moves = movesToCity;
1207           target_tile = dest;
1208         }
1209     }
1210
1211   if (cityNeeds) {
1212     debug("stack is sent to reinforce " << cityNeeds->getName() <<" if possible")
1213     // don't forget to send the stack to a free field within the city
1214     if (target_tile != Vector<int>(-1,-1))
1215       {
1216         d_analysis->reinforce(cityNeeds, s, moves);
1217         bool killed = false;
1218         bool moved = moveStack(s, target_tile, killed);
1219         return moved;
1220       }
1221   }
1222
1223   //okay, no city needed us, just try to reinforce our nearest city
1224   City *target = allCities->getNearestFriendlyCity(s->getPos());
1225   if (!target) // no friendly city?
1226     return false;
1227   //are we already there?
1228   if (target->contains(s->getPos()))
1229     {
1230       return false;
1231     }
1232   else
1233     {
1234       Vector<int> dest = getFreeSpotInCity(target, s->size());
1235       if (dest == Vector<int>(-1, -1))
1236         return false;
1237       bool killed = false;
1238       bool moved = moveStack(s, dest, killed);
1239       return moved;
1240     }
1241   return 0;
1242 }
1243
1244 void AI_Allocation::searchRuin(Stack *stack, Ruin *ruin)
1245 {
1246   d_owner->stackSearchRuin(stack, ruin);
1247   // what to do if the ruin search fails?
1248 }
1249
1250 bool AI_Allocation::shuffleStacksWithinCity(City *city, Stack *stack,
1251                                             Vector<int> diff)
1252 {
1253   if (!city)
1254     return false;
1255   Vector<int> target = city->getPos() + diff;
1256   //groupStacks(stack);
1257   if (stack->getPos() == target)
1258     {
1259       debug("stack " << stack->getId() <<" at ("<<stack->getPos().x<<","<<stack->getPos().y<<") already in preferred position.");
1260       // already in the preferred position
1261       //groupStacks(stack);
1262       return false;
1263     }
1264
1265   std::list<Stack*> f = GameMap::getFriendlyStacks(target);
1266   assert (f.size() <= 1);
1267   Stack *join = NULL;
1268   if (f.size() == 1)
1269     join = f.front();
1270   if (!join)
1271     {
1272       debug("no stack to land on.  just moving there.");
1273       bool moved = shuffleStack(stack, target, false);
1274       setParked(stack, true);
1275       return moved;
1276     }
1277   else if (GameMap::canJoin(stack, target))
1278     {
1279       debug("hey there's a stack to land on at (" <<target.x <<"," <<target.y<<").  moving there.");
1280       bool moved = shuffleStack(stack, target, false);
1281       setParked(stack, true);
1282       return moved;
1283     }
1284   else if (join->isFull())
1285     {
1286       debug("recursing now");
1287       //recurse, but prefer a different tile.
1288       if (diff == Vector<int>(0,0))
1289         diff = Vector<int>(0,1);
1290       else if (diff == Vector<int>(0,1))
1291         diff = Vector<int>(1,0);
1292       else if (diff == Vector<int>(1,0))
1293         diff = Vector<int>(1,1);
1294       else if (diff == Vector<int>(1,1))
1295         return false;
1296       return shuffleStacksWithinCity(city, stack, diff);
1297     }
1298   else
1299     {
1300       debug("alright, we're going to move what we can");
1301       bool moved = shuffleStack(stack, target, true);
1302       return moved;
1303     }
1304   return false;
1305 }
1306
1307 bool AI_Allocation::shuffleStack(Stack *stack, Vector<int> dest, bool split_if_necessary)
1308 {
1309   Stack *s = stack;
1310   assert (s != NULL);
1311   d_owner->getStacklist()->setActivestack(s);
1312   Path *p = new Path();
1313   p->push_back(dest);
1314   s->setPath(*p);
1315   delete p;
1316   if (s->enoughMoves())
1317     s->getPath()->setMovesExhaustedAtPoint(1);
1318   else
1319     s->getPath()->setMovesExhaustedAtPoint(0);
1320   Vector<int> src = s->getPos();
1321   bool moved;
1322
1323   if (split_if_necessary)
1324     {
1325       //the new stack is left behind, and the current stack goes forward.
1326       Stack *new_stack = NULL;
1327       moved = d_owner->stackSplitAndMove(s, new_stack);
1328       if (new_stack)
1329         {
1330           if (moved)
1331             {
1332               groupStacks(s);
1333               setParked(s, true);
1334             }
1335           groupStacks(new_stack);
1336           setParked(new_stack, true);
1337           return moved;
1338         }
1339     }
1340   else
1341     moved = d_owner->stackMove(s);
1342       
1343   groupStacks(s);
1344
1345   debug("shuffleStack on stack id " << s->getId() <<" has moved from " <<
1346         src.x << "," << src.y <<" to "
1347         << s->getPos().x << "," << s->getPos().y << ".");
1348   return moved;
1349 }
1350
1351 bool AI_Allocation::moveStack(Stack *stack, bool &stack_died)
1352 {
1353   guint32 stack_id = stack->getId();
1354   Stack *s = stack;
1355   assert (s != NULL);
1356   d_owner->getStacklist()->setActivestack(s);
1357   Vector<int> src = s->getPos();
1358   bool moved;
1359
1360   //printf("going in, size of path for stack: %d\n", s->getPath()->size());
1361   MoveResult *moveResult = d_owner->stackMove(s, Vector<int>(-1,-1));
1362   //printf("fight result is %d\n", moveResult->getFightResult());
1363   //printf("took steps? %d\n", moveResult->getStepCount());
1364   //printf("size of path for stack: %d\n", s->getPath()->size());
1365   //printf("reached end of path? %d\n", moveResult->getReachedEndOfPath());
1366   //printf("out of moves? %d\n", moveResult->getOutOfMoves());
1367   //printf("too large stack in the way? %d\n", moveResult->getTooLargeStackInTheWay());
1368   moved = moveResult->didSomething();
1369   delete moveResult;
1370   if (d_owner->getActivestack() == NULL)
1371     {
1372       debug("stack id " << stack_id << " died")
1373       stack_died = true;
1374     }
1375   else
1376     {
1377       groupStacks(s);
1378       stack_died = false;
1379       debug("Player " << d_owner->getName() << " moveStack on stack id " << s->getId() <<" has moved from " <<
1380             src.x << "," << src.y <<" to "
1381             << s->getPos().x << "," << s->getPos().y << ".  moved is " << moved << ".  moves left is " << s->getMoves() <<".");
1382     }
1383   return moved;
1384 }
1385
1386 bool AI_Allocation::moveStack(Stack *stack, Vector<int> dest, bool &stack_died)
1387 {
1388   Stack *s = stack;
1389   assert (s != NULL);
1390   int mp = s->getPath()->calculate(s, dest);
1391   if (mp <= 0)
1392     return false;
1393   return moveStack(s, stack_died);
1394 }
1395
1396 void AI_Allocation::setParked(Stack *stack, bool force_park)
1397 {
1398   if (!stack)
1399     return;
1400   if (force_park == false)
1401     {
1402       if (stack->hasPath() > 0 && stack->enoughMoves())
1403         stack->setParked(true);
1404       else if (stack->canMove() == false)
1405         stack->setParked(true);
1406     }
1407   else
1408     stack->setParked(true);
1409 }
1410
1411 bool AI_Allocation::groupStacks(Stack *stack)
1412 {
1413   Stack *s = stack;
1414   debug("groupStacks on stack id " << stack->getId() << " at pos (" << s->getPos().x <<"," <<s->getPos().y<<")");
1415   //which friendly stacks are on that tile that aren't us?
1416   std::list<Stack*> stks = GameMap::getFriendlyStacks(s->getPos());
1417   if (stks.size() <= 1)
1418     {
1419       if (stks.front()->getId() != stack->getId())
1420         {
1421           printf("whoops\n");
1422           printf("expected stack id %d, but got %d\n", stack->getId(), stks.front()->getId());
1423           assert(0);
1424         }
1425       assert (stks.front()->getId() == stack->getId());
1426       setParked(s);
1427       return false;
1428     }
1429   GameMap::groupStacks(s);
1430   setParked(s);
1431   return true;
1432 }
1433
1434 bool AI_Allocation::checkAmbiguities()
1435 {
1436   //Stack *bobo = d_owner->getStacklist()->getStackById(4416);
1437   //if (bobo)
1438     //{
1439       //printf ("stack 4416 parked? %d\n", bobo->getParked());
1440     //}
1441   return false;
1442     int count = 0;
1443     Stacklist *sl = d_owner->getStacklist();
1444     for (Stacklist::iterator it = sl->begin(); it != sl->end(); it++)
1445       {
1446         if (GameMap::getFriendlyStacks((*it)->getPos()).size() > 1)
1447           {
1448             printf("stack id %d at %d,%d sits on the same tile as:\n", 
1449                    (*it)->getId(),
1450                    (*it)->getPos().x, (*it)->getPos().y);
1451             std::list<Stack*> o = GameMap::getFriendlyStacks((*it)->getPos());
1452             for (std::list<Stack*>::iterator i = o.begin(); i != o.end(); i++)
1453               {
1454                 if ((*i)->getId() == (*it)->getId())
1455                   continue;
1456                 printf("stack %d\n", (*i)->getId());
1457               }
1458             count++;
1459           }
1460       }
1461     if (count > 0)
1462       exit(0);
1463     return count != 0;
1464 }
1465 // End of file