~ubuntu-branches/ubuntu/maverick/lordsawar/maverick

« back to all changes in this revision

Viewing changes to src/AI_Allocation.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Barry deFreese
  • Date: 2010-04-10 09:29:33 UTC
  • mfrom: (1.1.9 upstream) (5.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20100410092933-23uq4dxig30kmtcw
Tags: 0.1.8-1
* New upstream release.
* Add misc:Depends for -data package.
* Bump Standards Version to 3.8.4. (No changes needed).

Show diffs side-by-side

added added

removed removed

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