1 // Copyright (C) 2004 John Farrell
2 // Copyright (C) 2004, 2005, 2006, 2007 Ulf Lorenz
3 // Copyright (C) 2008, 2009 Ben Asselstine
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.
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.
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
22 #include "AI_Analysis.h"
23 #include "AI_Allocation.h"
25 #include "playerlist.h"
27 #include "stacklist.h"
31 #include "MoveResult.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"
44 #include "QKillHero.h"
45 #include "QEnemyArmies.h"
46 #include "QEnemyArmytype.h"
50 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<flush<<endl;}
53 AI_Allocation* AI_Allocation::s_instance = 0;
56 AI_Allocation::AI_Allocation(AI_Analysis *analysis, const Threatlist *threats, Player *owner)
57 :d_owner(owner), d_analysis(analysis), d_threats(threats)
62 AI_Allocation::~AI_Allocation()
67 StackReflist::iterator AI_Allocation::eraseStack(StackReflist::iterator it)
70 return d_stacks->eraseStack(it);
72 void AI_Allocation::deleteStack(Stack* s)
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
80 s_instance->setParked(s, true);
81 s_instance->d_stacks->removeStack(s->getId());
85 int AI_Allocation::allocateStackToCapacityBuilding(Threat *threat, City *first_city, bool take_neutrals)
90 pos = threat->getClosestPoint(first_city->getPos());
91 else if (d_owner->getStacklist()->size() > 0)
92 pos = threat->getClosestPoint(d_owner->getStacklist()->front()->getPos());
95 City *c =GameMap::getEnemyCity(pos);
98 if (c->isBurnt() == true)
100 if (c->getOwner() == Playerlist::getInstance()->getNeutral() && take_neutrals == false)
102 Stack *attacker = findClosestStackToEnemyCity(c, take_neutrals);
105 Vector<int> dest = threat->getClosestPoint(attacker->getPos());
107 //only take what we need.
108 std::list<guint32> armies = attacker->determineStrongArmies(3.0);
109 if (armies.size() > 0 && armies.size() != attacker->size())
111 Stack *stack = d_owner->stackSplitArmies(attacker, armies);
112 moved = moveStack(stack, dest, killed);
115 if (stack->hasPath() == false)
116 d_stacks->addStack(stack);
121 moved = moveStack(attacker, dest, killed);
124 if (attacker->hasPath() == true)
125 deleteStack(attacker);
131 int AI_Allocation::allocateStacksToCapacityBuilding(City *first_city,
136 for (Threatlist::const_iterator it = d_threats->begin();
137 it != d_threats->end(); it++)
140 if (d_stacks->size() == 0)
142 if (t->isCity() && t->getStrength() <= 0.5003)
144 if (allocateStackToCapacityBuilding(*it, first_city, take_neutrals))
153 bool AI_Allocation::continueQuest(Quest *quest, Stack *stack)
155 Vector<int> dest = d_owner->AI_getQuestDestination(quest, stack);
156 if (dest == Vector<int>(-1,-1))
159 bool moved = moveStack(stack, dest, killed);
168 int AI_Allocation::continueQuests()
171 if (GameScenarioOptions::s_play_with_quests == GameParameters::NO_QUESTING)
174 std::vector<Quest*> quest =
175 QuestsManager::getInstance()->getPlayerQuests(d_owner);
176 for (std::vector<Quest*>::iterator i = quest.begin(); i != quest.end(); i++)
179 if (quest->isPendingDeletion())
181 Stack *s = d_owner->getStacklist()->getArmyStackById(quest->getHeroId());
182 bool moved = continueQuest(quest, s);
189 int AI_Allocation::continueAttacks()
192 for (StackReflist::iterator i = d_stacks->begin(); i != d_stacks->end(); i++)
195 if (s->getParked() == false && s->isOnCity() == false &&
196 s->hasPath() == true &&
197 GameMap::getEnemyCity(s->getLastPointInPath()) != NULL)
200 bool moved = moveStack(s, killed);
205 if (s->hasPath() == true)
211 if (s->isOnCity() == true)
212 shuffleStacksWithinCity(GameMap::getCity(s), s,
222 int AI_Allocation::attackNearbyEnemies()
225 Citylist *cl = Citylist::getInstance();
226 for (Citylist::iterator i = cl->begin(); i != cl->end(); i++)
229 if (d_owner->abortRequested())
231 if (d_stacks->size() == 0)
234 if (city->getOwner() == d_owner || city->isBurnt() == true)
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++)
239 Stack *s = GameMap::getFriendlyStack(*j);
242 if (s->getParked() == false && s->getMoves() >= 4)
246 moved = moveStack(s, city->getNearestPos(s->getPos()), killed);
249 if (s->hasPath() == true)
251 else if (s->isOnCity() == true)
254 shuffleStacksWithinCity(GameMap::getCity(s), s,
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++)
272 if (d_owner->abortRequested())
274 Stack *s = GameMap::getFriendlyStack(*i);
277 if (d_stacks->size() == 0)
279 if (s->isOnCity() == true)
281 if (s->getParked() == true)
283 std::list<Vector<int> > p = GameMap::getNearbyPoints(*i, 2);
284 for (std::list<Vector<int> >::iterator j = p.begin(); j != p.end(); j++)
286 Stack *enemy = GameMap::getEnemyStack(*j);
291 if (enemy->isOnCity() == true)
293 if (s->size() < enemy->size())
295 if (s->hasShip() != enemy->hasShip())
297 moved = moveStack(s, enemy->getPos(), killed);
302 if (s->hasPath() == true)
312 bool AI_Allocation::emptyOutCities()
314 //everybody out on the dancefloor.
315 Citylist *cl = Citylist::getInstance();
316 for (Citylist::iterator it = cl->begin(); it != cl->end(); it++)
320 if (d_owner->abortRequested())
323 if (c->getOwner() != d_owner || c->isBurnt() == true)
326 guint32 num_defenders = c->countDefenders();
327 for (guint i = 0; i < c->getSize(); i++)
329 for (guint j = 0; j < c->getSize(); j++)
331 Stack *s = GameMap::getStack(c->getPos() + Vector<int>(i,j));
334 if ((s->getMoves() > 3 && s->size() >= 4 &&
335 (num_defenders - s->size()) >= 3) || (rand() % 10) == 0)
337 City *target = cl->getNearestEnemyCity(s->getPos());
341 if (d_stacks->contains(s->getId()) == false)
342 d_stacks->addStack(s);
343 moveStack(s, target->getNearestPos(s->getPos()), killed);
351 if (d_owner->getGold() < 20)
360 int AI_Allocation::visitTemples(bool get_quests)
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++)
367 Stack *s = GameMap::getFriendlyStack(*i);
370 if (s->isOnCity() == true)
372 if (s->hasHero() && get_quests)
376 moved = d_owner->AI_maybeVisitTempleForQuest(s, s->getMoves(),
381 //if (!killed && moved && s->hasPath() == true)
388 bool blessed = false;
389 moved = d_owner->AI_maybeVisitTempleForBlessing(s, s->getMoves(),
391 50.0, blessed, killed);
394 //if (!killed && moved && s->hasPath() == true)
401 int AI_Allocation::visitRuins()
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++)
408 Stack *s = GameMap::getFriendlyStack(*i);
411 if (s->isOnCity() == true)
417 moved = d_owner->AI_maybeVisitRuin(s, s->getMoves(),
418 s->getMoves() + 17, killed);
421 //if (!killed && moved && s->hasPath() == true)
428 int AI_Allocation::pickupItems()
431 if (d_owner->getHeroes().size() == 0)
433 std::vector<Vector<int> > items = GameMap::getInstance()->getItems();
434 for (std::vector<Vector<int> >::iterator i = items.begin(); i != items.end();
437 std::list<Stack*> s = GameMap::getNearbyFriendlyStacks(*i, 8);
438 for (std::list<Stack*>::iterator j = s.begin(); j != s.end(); j++)
441 if (s->hasHero() == false)
443 if (GameMap::getEnemyCity(*i) != NULL)
445 if (s->isOnCity() == false)
448 if (moveStack(s, *i, killed))
453 if (s->getPos() == *i)
455 Hero *hero = dynamic_cast<Hero*>(s->getFirstHero());
456 d_owner->heroPickupAllItems (hero, *i);
464 City *c = GameMap::getCity(s->getPos());
465 if (c->contains(*i) == true)
468 if (moveStack(s, *i, killed))
473 if (s->getPos() == *i)
475 Hero *hero = dynamic_cast<Hero*>(s->getFirstHero());
476 d_owner->heroPickupAllItems (hero, *i);
489 int AI_Allocation::move(City *first_city, bool take_neutrals)
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;
495 d_stacks = new StackReflist(d_owner->getStacklist(), true);
497 int total = d_stacks->size();
498 debug("Player " << d_owner->getName() << " starts with " << d_stacks->size() << " stacks to do something with");
503 if (d_owner->abortRequested())
507 quest_alloc = d_stacks->size();
508 moved = continueQuests();
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.");
515 if (d_owner->abortRequested())
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.");
526 if (d_owner->abortRequested())
528 //move hero stacks to ruins for searching.
529 ruin_alloc = d_stacks->size();
530 moved = visitRuins();
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.");
537 if (d_owner->abortRequested())
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.");
548 if (d_owner->abortRequested())
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.");
559 if (d_owner->abortRequested())
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.");
570 if (d_owner->abortRequested())
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.");
586 if (d_owner->abortRequested())
588 defensive_alloc = d_stacks->size();
589 moved = allocateDefensiveStacks(Citylist::getInstance());
590 defensive_moved = moved;
591 defensive_alloc -= d_stacks->size();
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.");
598 if (d_stacks->size() == 0)
605 if (d_owner->abortRequested())
607 offensive_alloc = d_stacks->size();
608 moved = allocateStacksToThreats();
609 offensive_moved = moved;
610 offensive_alloc -= d_stacks->size();
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.");
617 if (d_stacks->size() == 0)
624 if (d_owner->abortRequested())
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.");
634 if (d_owner->abortRequested())
636 //empty out the cities damnit.
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 <<").");
644 //if (IIId_owner->getId() == 0)
649 int AI_Allocation::allocateDefensiveStacksToCity(City *city)
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)
657 else if (cityDanger > 10.0)
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++)
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));
669 std::vector<Stack*> defenders = city->getDefenders();
670 vector<Stack*>::iterator it;
671 for (it = defenders.begin(); it != defenders.end(); it++)
673 Stack *defender = *it;
674 if (defender->getParked() == true)
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)
681 totalDefenderStrength += stackStrength;
682 if (totalDefenderStrength > cityDanger)
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())
690 Vector<int> dest = getFreeOtherSpotInCity(city, defender);
691 if (dest != Vector<int>(-1,-1))
693 Stack *stack = d_owner->stackSplitArmies(defender,
695 if (stack->getMoves() > 0)
697 if (shuffleStack(stack, dest, false))
700 if (stack->getParked() == false)
701 d_stacks->addStack(stack);
705 groupStacks(defender);
709 deleteStack(defender);
714 deleteStack(defender);
716 // if we get here, we have assigned defenders but not enough to
717 // counter the danger that the city is in
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 )
726 Stack *s = findClosestStackToCity(city);
729 debug("City " << city->getName() << " is endangered but no stacks are close enough to go defend it (or no more space available in city).")
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))
736 float stackStrength = d_analysis->assessStackStrength(s);
737 totalDefenderStrength += stackStrength;
739 if (totalDefenderStrength > cityDanger)
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())
747 Stack *stack = d_owner->stackSplitArmies(s, armies);
748 d_stacks->addStack(stack);
755 if (moveStack(s, dest, killed))
761 if (totalDefenderStrength < cityDanger)
763 debug(city->getName() << " cannot be adequately defended")
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)
772 //we need to split the stacks and add the newly split ones to d_stacks.
774 for (Citylist::iterator it = cities->begin(); it != cities->end(); ++it)
777 if (!city->isFriend(d_owner) || city->isBurnt())
779 count += allocateDefensiveStacksToCity(city);
781 if (d_owner->abortRequested())
788 int AI_Allocation::allocateStacksToThreat(Threat *threat)
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)));
797 if (city && city->getOwner() == d_owner)
799 guint32 num_city_defenders = 0;
800 Stack *attacker = findBestAttackerFor(threat, num_city_defenders);
801 //if (attacker && attacker->getId() == 4207)
803 //printf("4207 was chosen for threat: `%s'\n", threat->toString().c_str());
805 // if there is nobody to attack the threat, go onto the next one
808 float score = d_analysis->assessStackStrength(attacker);
810 Vector<int> dest = threat->getClosestPoint(attacker->getPos());
811 //if (attacker->getId() == 4207)
813 //printf("dest is %d,%d\n", dest.x, dest.y);
816 if (num_city_defenders == 0 || num_city_defenders - attacker->size() > 3)
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))
826 if (attacker->isOnCity())
828 shuffleStacksWithinCity (GameMap::getCity(attacker),
829 attacker, Vector<int>(0,0));
830 //setParked(attacker, true);
838 std::list<guint32> armies = attacker->determineStrongArmies(3.0);
839 if (armies.size() > 0 && armies.size() != attacker->size())
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);
847 if (stack->hasPath() == false)
848 d_stacks->addStack(stack);
855 threat_danger -= score;
856 // if the threat has been removed, go onto the next one
857 if (threat->getStrength() == 0.0)
859 if (threat_danger <= 0)
865 int AI_Allocation::allocateStacksToThreats()
869 for (Threatlist::const_iterator it = d_threats->begin();
870 it != d_threats->end(); ++it)
873 count += allocateStacksToThreat(*it);
875 if (d_stacks->size() == 0)
878 if (d_owner->abortRequested())
885 Vector<int> AI_Allocation::getFreeOtherSpotInCity(City *city, Stack *stack)
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++)
893 Vector<int> pos = city->getPos() + Vector<int>(i,j);
894 if (pos == stack->getPos())
896 if (GameMap::canAddArmies(pos, stack->size()) == false)
898 std::list<Stack*> f = GameMap::getFriendlyStacks(pos);
901 for (std::list<Stack*>::iterator i = f.begin(); i != f.end(); i++)
903 if ((*i)->size() > size)
918 Vector<int> AI_Allocation::getFreeSpotInCity(City *city, int stackSize)
920 for (unsigned int i = 0; i < city->getSize(); i++)
921 for (unsigned int j = 0; j < city->getSize(); j++)
923 Vector<int> pos = city->getPos() + Vector<int>(i,j);
924 if (GameMap::canAddArmies(pos, stackSize) == false)
928 //there's no room in the inn.
929 return Vector<int>(-1,-1);
932 Stack *AI_Allocation::findClosestStackToEnemyCity(City *city, bool try_harder)
934 Vector<int> pos = city->getPos();
937 for (StackReflist::iterator it = d_stacks->begin(); it != d_stacks->end(); ++it)
940 if (s->getParked() == true)
943 int tiles = dist(city->getPos(), s->getPos());
946 int moves = (tiles + 6) / 7;
948 if (try_harder == false && s->isOnCity())
950 City *source_city = GameMap::getCity(s);
953 if (d_analysis->getNumberOfDefendersInCity(source_city) <=
959 if (moves < lowest_mp || lowest_mp == -1)
968 Stack *AI_Allocation::findClosestStackToCity(City *city)
970 Vector<int> pos = city->getPos();
973 for (StackReflist::iterator it = d_stacks->begin(); it != d_stacks->end(); ++it)
976 if (s->getParked() == true)
978 //don't consider the stack if it's already in the city
979 Vector<int> spos = s->getPos();
980 if (city->contains(spos))
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))
986 //don't consider the stack if it's in an endangered city
987 City *source_city = GameMap::getCity(s);
990 if (d_analysis->getNumberOfDefendersInCity(source_city) <= 3)
994 int tiles = dist(city->getPos(), s->getPos());
995 int moves = (tiles + 6) / 7;
996 if (moves < lowest_mp || lowest_mp == -1)
1005 Stack *AI_Allocation::findBestAttackerFor(Threat *threat, guint32 &city_defenders)
1008 float best_score = -1.0;
1009 for (StackReflist::iterator it = d_stacks->begin(); it != d_stacks->end(); ++it)
1012 if (s->getParked() == true)
1014 Vector<int> closestPoint = threat->getClosestPoint(s->getPos());
1015 // threat has been destroyed anyway
1016 if (closestPoint.x == -1)
1018 Vector<int> spos = s->getPos();
1020 int distToThreat = dist(closestPoint, spos);
1021 if (distToThreat > 27)
1023 else if (distToThreat == 0)
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;
1031 num_source_city_defenders =
1032 d_analysis->getNumberOfDefendersInCity(source_city);
1033 if (num_source_city_defenders <= (3 + 4))
1037 int score = d_analysis->assessStackStrength(s);
1038 if (score > best_score || best_score == -1.0)
1042 city_defenders = num_source_city_defenders;
1048 int AI_Allocation::defaultStackMovements()
1051 Citylist *allCities = Citylist::getInstance();
1052 debug("Default movement for " <<d_stacks->size() <<" stacks");
1054 while (d_stacks->size() > 0)
1057 if (d_owner->abortRequested())
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<<")");
1064 City *source_city = GameMap::getCity(s);
1068 source_city->countDefenders() - s->isFull() > 3)
1077 City* enemyCity = allCities->getNearestEnemyCity(s->getPos());
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");
1084 bool killed = false;
1085 moved = moveStack(s, killed);
1089 shuffleStacksWithinCity (GameMap::getCity(s), s,
1091 //setParked(s, true);
1099 enemyCity = allCities->getNearestForeignCity(s->getPos());
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()));
1108 bool killed = false;
1109 moved = moveStack(s, killed);
1113 shuffleStacksWithinCity (GameMap::getCity(s),
1114 s, Vector<int>(0,0));
1115 //setParked(s, true);
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.")
1131 MoveResult *result = 0;
1132 for (Citylist::iterator cit = allCities->begin(); cit != allCities->end(); cit++)
1133 if ((*cit)->getOwner() != d_owner)
1135 debug("Let's try "<<(*cit).getName() <<" instead.")
1136 result = moveStack(s, (*cit)->getPos());
1137 if (result && result->moveSucceeded())
1152 //moved = stackReinforce(s);
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.
1170 bool AI_Allocation::stackReinforce(Stack *s)
1172 Citylist *allCities = Citylist::getInstance();
1173 float mostNeeded = -1000.0;
1174 City *cityNeeds = 0;
1176 Vector<int> target_tile = Vector<int>(-1,-1);
1177 for (Citylist::iterator it = allCities->begin(); it != allCities->end(); ++it)
1180 if (city->getOwner() != d_owner)
1182 if (city->isBurnt() == true)
1184 int distToCity = dist(s->getPos(), city->getPos());
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()))
1191 //disregard if the city is too far away
1192 int movesToCity = (distToCity + 6) / 7;
1193 if (movesToCity > 3) continue;
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))
1200 //pick the city that needs us the most
1201 float need = d_analysis->reinforcementsNeeded(city);
1202 if (need > mostNeeded)
1206 moves = movesToCity;
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))
1216 d_analysis->reinforce(cityNeeds, s, moves);
1217 bool killed = false;
1218 bool moved = moveStack(s, target_tile, killed);
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?
1227 //are we already there?
1228 if (target->contains(s->getPos()))
1234 Vector<int> dest = getFreeSpotInCity(target, s->size());
1235 if (dest == Vector<int>(-1, -1))
1237 bool killed = false;
1238 bool moved = moveStack(s, dest, killed);
1244 void AI_Allocation::searchRuin(Stack *stack, Ruin *ruin)
1246 d_owner->stackSearchRuin(stack, ruin);
1247 // what to do if the ruin search fails?
1250 bool AI_Allocation::shuffleStacksWithinCity(City *city, Stack *stack,
1255 Vector<int> target = city->getPos() + diff;
1256 //groupStacks(stack);
1257 if (stack->getPos() == target)
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);
1265 std::list<Stack*> f = GameMap::getFriendlyStacks(target);
1266 assert (f.size() <= 1);
1272 debug("no stack to land on. just moving there.");
1273 bool moved = shuffleStack(stack, target, false);
1274 setParked(stack, true);
1277 else if (GameMap::canJoin(stack, target))
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);
1284 else if (join->isFull())
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))
1296 return shuffleStacksWithinCity(city, stack, diff);
1300 debug("alright, we're going to move what we can");
1301 bool moved = shuffleStack(stack, target, true);
1307 bool AI_Allocation::shuffleStack(Stack *stack, Vector<int> dest, bool split_if_necessary)
1311 d_owner->getStacklist()->setActivestack(s);
1312 Path *p = new Path();
1316 if (s->enoughMoves())
1317 s->getPath()->setMovesExhaustedAtPoint(1);
1319 s->getPath()->setMovesExhaustedAtPoint(0);
1320 Vector<int> src = s->getPos();
1323 if (split_if_necessary)
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);
1335 groupStacks(new_stack);
1336 setParked(new_stack, true);
1341 moved = d_owner->stackMove(s);
1345 debug("shuffleStack on stack id " << s->getId() <<" has moved from " <<
1346 src.x << "," << src.y <<" to "
1347 << s->getPos().x << "," << s->getPos().y << ".");
1351 bool AI_Allocation::moveStack(Stack *stack, bool &stack_died)
1353 guint32 stack_id = stack->getId();
1356 d_owner->getStacklist()->setActivestack(s);
1357 Vector<int> src = s->getPos();
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();
1370 if (d_owner->getActivestack() == NULL)
1372 debug("stack id " << stack_id << " died")
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() <<".");
1386 bool AI_Allocation::moveStack(Stack *stack, Vector<int> dest, bool &stack_died)
1390 int mp = s->getPath()->calculate(s, dest);
1393 return moveStack(s, stack_died);
1396 void AI_Allocation::setParked(Stack *stack, bool force_park)
1400 if (force_park == false)
1402 if (stack->hasPath() > 0 && stack->enoughMoves())
1403 stack->setParked(true);
1404 else if (stack->canMove() == false)
1405 stack->setParked(true);
1408 stack->setParked(true);
1411 bool AI_Allocation::groupStacks(Stack *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)
1419 if (stks.front()->getId() != stack->getId())
1422 printf("expected stack id %d, but got %d\n", stack->getId(), stks.front()->getId());
1425 assert (stks.front()->getId() == stack->getId());
1429 GameMap::groupStacks(s);
1434 bool AI_Allocation::checkAmbiguities()
1436 //Stack *bobo = d_owner->getStacklist()->getStackById(4416);
1439 //printf ("stack 4416 parked? %d\n", bobo->getParked());
1443 Stacklist *sl = d_owner->getStacklist();
1444 for (Stacklist::iterator it = sl->begin(); it != sl->end(); it++)
1446 if (GameMap::getFriendlyStacks((*it)->getPos()).size() > 1)
1448 printf("stack id %d at %d,%d sits on the same tile as:\n",
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++)
1454 if ((*i)->getId() == (*it)->getId())
1456 printf("stack %d\n", (*i)->getId());