initial commit, lordsawar source, slightly modified
[lordsawar] / src / ai_smart.cpp
1 // Copyright (C) 2004 John Farrell
2 // Copyright (C) 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2005, 2006 Andrea Paternesi
4 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
5 // Copyright (C) 2007, 2008 Ole Laursen
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License as published by
9 //  the Free Software Foundation; either version 3 of the License, or
10 //  (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU Library General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
20 //  02110-1301, USA.
21
22 #include <stdlib.h>
23 #include <algorithm>
24 #include <map>
25
26 #include "ai_smart.h"
27 #include "playerlist.h"
28 #include "armysetlist.h"
29 #include "stacklist.h"
30 #include "path.h"
31 #include "AI_Analysis.h"
32 #include "AI_Allocation.h"
33 #include "AI_Diplomacy.h"
34 #include "action.h"
35 #include "xmlhelper.h"
36 #include "armyprodbase.h"
37 #include "armyproto.h"
38 #include "history.h"
39 #include "citylist.h"
40 #include "city.h"
41 #include "Sage.h"
42
43 using namespace std;
44
45 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<flush<<endl;}
46 //#define debug(x)
47
48 AI_Smart::AI_Smart(string name, unsigned int armyset, Gdk::Color color, int width, int height, int player_no)
49   :RealPlayer(name, armyset, color, width, height, Player::AI_SMART, player_no),
50    d_mustmakemoney(0)
51 {
52 }
53
54 AI_Smart::AI_Smart(const Player& player)
55     :RealPlayer(player),d_mustmakemoney(0)
56 {
57     d_type = AI_SMART;
58 }
59
60 AI_Smart::AI_Smart(XML_Helper* helper)
61     :RealPlayer(helper),d_mustmakemoney(0)
62 {
63 }
64
65 AI_Smart::~AI_Smart()
66 {
67 }
68
69 bool AI_Smart::startTurn()
70 {
71   sbusy.emit();
72
73   if (getStacklist()->getHeroes().size() == 0 &&
74       Citylist::getInstance()->countCities(this) == 1)
75     AI_maybeBuyScout(Citylist::getInstance()->getFirstCity(this));
76   
77     debug("Player " << getName() << " starts a turn.")
78
79     AI_Diplomacy diplomacy (this);
80
81     diplomacy.considerCuspOfWar();
82
83     if (getGold() < 500 && getUpkeep() > getIncome())
84       d_mustmakemoney = 1;
85     else
86       d_mustmakemoney = 0;
87
88     // the real stuff
89     examineCities();
90
91     AI_setupVectoring(10, 3, 20);
92
93     sbusy.emit();
94     //int loopCount = 0;
95         
96     AI_Analysis *analysis = new AI_Analysis(this);
97     const Threatlist *threats = analysis->getThreatsInOrder();
98     City *first_city = Citylist::getInstance()->getFirstCity(this);
99     bool build_capacity = false;
100     if (first_city)
101       {
102         Vector<int> pos = first_city->getPos();
103         City *first_neutral = 
104           Citylist::getInstance()->getNearestNeutralCity(pos);
105         if (first_neutral)
106           {
107             if (dist (pos, first_neutral->getPos()) <= 50)
108               build_capacity = true;
109           }
110       }
111     if (getGold() < 30)
112       build_capacity = true;
113     while (true)
114     {
115         sbusy.emit();
116         
117         AI_Allocation *allocation = new AI_Allocation(analysis, threats, this);
118         allocation->sbusy.connect 
119           (sigc::mem_fun (sbusy, &sigc::signal<void>::emit));
120         int moveCount = allocation->move(first_city, build_capacity);
121         
122         // tidying up
123         delete allocation;
124         
125         // stop when no more stacks move
126         if (moveCount == 0)
127             break;
128         if (abort_requested)
129           break;
130     }
131         
132     delete analysis;
133     d_stacklist->setActivestack(0);
134
135     diplomacy.makeProposals();
136     
137     if (abort_requested)
138       aborted_turn.emit();
139     return true;
140 }
141
142 void AI_Smart::abortTurn()
143 {
144   abort_requested = true;
145   if (surrendered)
146     aborted_turn.emit();
147   else if (Playerlist::getInstance()->countPlayersAlive() == 1)
148     aborted_turn.emit();
149 }
150
151 void AI_Smart::invadeCity(City* c)
152 {
153   CityDefeatedAction action = CITY_DEFEATED_OCCUPY;
154   AI_invadeCityQuestPreference(c, action);
155
156   int gold = 0;
157   int pillaged_army_type = -1;
158   std::list<guint32> sacked_army_types;
159   switch (action)
160     {
161     case CITY_DEFEATED_OCCUPY:
162       cityOccupy(c);
163       break;
164     case CITY_DEFEATED_PILLAGE:
165       cityPillage(c, gold, &pillaged_army_type);
166       break;
167     case CITY_DEFEATED_RAZE:
168       cityRaze(c);
169       break;
170     case CITY_DEFEATED_SACK:
171       citySack(c, gold, &sacked_army_types);
172       break;
173     }
174
175   if (c->getNoOfProductionBases() == 0)
176     maybeBuyProduction(c, true);
177
178   // Update its production
179   setProduction(c);
180 }
181
182 void AI_Smart::heroGainsLevel(Hero * a)
183 {
184     Army::Stat stat = Army::STRENGTH;
185     doHeroGainsLevel(a, stat);
186
187     Action_Level* item = new Action_Level();
188     item->fillData(a, stat);
189     addAction(item);
190 }
191
192 int AI_Smart::maybeBuyProduction(City *c, bool quick)
193 {
194   Armysetlist *al = Armysetlist::getInstance();
195   int freeslot = -1;
196
197   int armytype = -1;
198
199   freeslot = c->getFreeSlot();
200
201   if (freeslot==-1)
202     return -1;
203
204   armytype = chooseArmyTypeToBuy(c, quick);
205   //does this armytype beat the one we're currently producing?
206   //is the one we're buying any better ?
207   if (armytype == -1)
208     return -1;
209
210   bool buy = false;
211   int slot = c->getActiveProductionSlot();
212   if (slot == -1)
213     buy = true;
214   else if (scoreBestArmyType(al->getArmy(getArmyset(), armytype)) > 
215            scoreBestArmyType(c->getProductionBase(slot)))
216     buy = true;
217
218   if (buy)
219     {
220       debug("armytype i want to produce " << armytype);
221
222       bool couldbuy = cityBuyProduction(c, freeslot, armytype);
223
224       if (armytype >= 0 && couldbuy)
225         {
226           debug("YES I COULD BUY! type=" << armytype) 
227             return armytype;
228         }
229     }
230   return -1;
231 }
232
233 int AI_Smart::setQuickProduction(City *c)
234 {
235   int select = -1;
236   int best_score = -1;
237
238   // we try to determine the most attractive basic production
239   for (guint32 i = 0; i < c->getMaxNoOfProductionBases(); i++)
240     {
241       if (c->getArmytype(i) == -1)    // no production in this slot
242         continue;
243
244       const ArmyProdBase *proto = c->getProductionBase(i);
245       int score = scoreQuickArmyType(proto);
246       if (score > best_score)
247         {
248           select = i;
249           best_score = score;
250         }
251     }
252
253   if (select != c->getActiveProductionSlot())
254     {
255       cityChangeProduction(c, select);
256       debug(getName() << " Set production to " << select << " in " << c->getName())
257     }
258
259   return c->getActiveProductionSlot();
260 }
261
262 int AI_Smart::setBestProduction(City *c)
263 {
264   int select = -1;
265   int best_score = -1;
266
267   // we try to determine the most attractive basic production
268   for (guint32 i = 0; i < c->getMaxNoOfProductionBases(); i++)
269     {
270       if (c->getArmytype(i) == -1)    // no production in this slot
271         continue;
272
273       const ArmyProdBase *proto = c->getProductionBase(i);
274       int score = scoreBestArmyType(proto);
275       if (score > best_score)
276         {
277           select = i;
278           best_score = score;
279         }
280     }
281
282   if (select != c->getActiveProductionSlot())
283     {
284       cityChangeProduction(c, select);
285       debug(getName() << " Set production to slot " << select << " in " << c->getName())
286     }
287
288   return c->getActiveProductionSlot();
289 }
290
291 int AI_Smart::chooseArmyTypeToBuy(City *c, bool quick)
292 {
293     int bestScore, bestIndex;
294     guint32 size = 0;
295
296     const Armysetlist* al = Armysetlist::getInstance();
297
298     size = al->getSize(getArmyset());
299         
300     bestScore = -1;
301     bestIndex = -1;
302     
303     debug("size " << size)
304
305     for (unsigned int i = 0; i < size; i++)
306     {
307         const ArmyProto *proto = NULL;
308
309         proto=al->getArmy(getArmyset(), i);
310
311         if (proto->getNewProductionCost() == 0)
312           continue;
313
314         if ((int)proto->getNewProductionCost() > d_gold)
315           continue;
316         
317        if (c->hasProductionBase(proto->getTypeId(), getArmyset())==false)
318        {
319          int score;
320          if (quick)
321            score = scoreQuickArmyType(proto);
322          else
323            score = scoreBestArmyType(proto);
324          if (score >= bestScore)
325          {
326             bestIndex = i;
327             bestScore = score;
328          }
329        }
330     }
331
332     return bestIndex;
333 }
334
335 int AI_Smart::scoreQuickArmyType(const ArmyProdBase *a)
336 {
337   //go get the best 1 turn army with the highest strength
338   int strength = a->getStrength();
339
340   int production = (5 - a->getProduction()) * 10;
341   return strength + production;
342 }
343
344 int AI_Smart::scoreQuickArmyType(const ArmyProto *a)
345 {
346   //go get the best 1 turn army with the highest strength
347   int strength = a->getStrength();
348
349   int production = (5 - a->getProduction()) * 10;
350   return strength + production;
351 }
352
353 int AI_Smart::scoreBestArmyType(const ArmyProto *a)
354 {
355   int production = a->getProduction();
356   if (production == 3)
357     production = 4;
358   //this treats armies with turns of 7 or higher unfairly
359   int max_strength = 60 / production * a->getStrength();
360
361   int city_bonus = 0;
362   switch (a->getArmyBonus())
363     {
364     case Army::ADD1STRINCITY: city_bonus += 5; break;
365     case Army::ADD2STRINCITY: city_bonus += 10; break;
366     }
367
368   int any_other_bonus = 0;
369   if (a->getArmyBonus() && city_bonus == 0)
370     any_other_bonus += 2;
371
372   int move_bonus = 0;
373   if (a->getMaxMoves() >  10)
374     move_bonus += 2;
375   if (a->getMaxMoves() >=  20)
376     move_bonus += 4;
377
378   return max_strength + city_bonus + move_bonus + any_other_bonus;
379 }
380
381 int AI_Smart::scoreBestArmyType(const ArmyProdBase *a)
382 {
383   //this treats armies with turns of 7 or higher unfairly
384   int max_strength = 60 / a->getProduction() * a->getStrength();
385
386   int city_bonus = 0;
387   switch (a->getArmyBonus())
388     {
389     case Army::ADD1STRINCITY: city_bonus += 5; break;
390     case Army::ADD2STRINCITY: city_bonus += 10; break;
391     }
392
393   int any_other_bonus = 0;
394   if (a->getArmyBonus() && city_bonus == 0)
395     any_other_bonus += 2;
396
397   int move_bonus = 0;
398   if (a->getMaxMoves() >  10)
399     move_bonus += 2;
400   if (a->getMaxMoves() >=  20)
401     move_bonus += 4;
402
403   return max_strength + city_bonus + move_bonus + any_other_bonus;
404 }
405
406 bool AI_Smart::cityNewlyTaken(City *city, guint32 turns) const
407 {
408   guint count = 0;
409   std::list<History*> h = getHistoryForCityId(city->getId());
410   for (std::list<History*>::reverse_iterator i = h.rbegin(); i != h.rend(); i++)
411     {
412       if ((*i)->getType() == History::START_TURN)
413         count++;
414       else if ((*i)->getType() == History::CITY_WON)
415         break;
416     }
417
418   if (count >= turns)
419     return true;
420   return false;
421 }
422
423 void AI_Smart::setProduction(City *city)
424 {
425   if (city->countDefenders() < 3 || cityNewlyTaken(city) == true)
426     {
427       int slot = setQuickProduction(city);
428       if (slot == -1)
429         {
430           slot = maybeBuyProduction(city, true);
431           if (slot != -1)
432             cityChangeProduction(city, slot);
433         }
434     }
435   else
436     {
437       setBestProduction(city);
438     }
439 }
440
441 void AI_Smart::examineCities()
442 {
443   debug("Examinating Cities to see what we can do");
444   Citylist* cl = Citylist::getInstance();
445   for (Citylist::iterator it = cl->begin(); it != cl->end(); ++it)
446     {
447       City *city = (*it);
448       if (city->getOwner() == this && city->isBurnt() == false)
449         setProduction(city);
450     }
451   //do we have enough money to create all these new-fangled army units?
452   int profit = getIncome() - getUpkeep();
453   int total_gp_to_spend = getGold() + profit;
454   //now we get to spend this amount on the city production.
455   //we'll turn off the cities we can't afford.
456   std::list<City*> cities = cl->getNearestFriendlyCities(this);
457   for (std::list<City*>::iterator it = cities.begin(); it != cities.end(); it++)
458     {
459       City *c = *it;
460       if (total_gp_to_spend <= 0)
461         cityChangeProduction(c, -1);
462       else
463         {
464           const ArmyProdBase *prodbase = c->getActiveProductionBase();
465           if (prodbase)
466             {
467               total_gp_to_spend -= prodbase->getProductionCost();
468               if (total_gp_to_spend <= 0)
469                 cityChangeProduction(c, -1);
470             }
471         }
472     }
473 }
474
475 bool AI_Smart::chooseTreachery (Stack *stack, Player *player, Vector <int> pos)
476 {
477   bool performTreachery = true;
478   return performTreachery;
479 }
480
481 bool AI_Smart::chooseHero(HeroProto *hero, City *city, int gold)
482 {
483   return true;
484 }
485
486 Reward *AI_Smart::chooseReward(Ruin *ruin, Sage *sage, Stack *stack)
487 {
488   //always pick the money.
489   for (Sage::iterator it = sage->begin(); it != sage->end(); it++)
490     if ((*it)->getType() == Reward::GOLD)
491       return (*it);
492   return sage->front();
493 }
494
495 Army::Stat AI_Smart::chooseStat(Hero *hero)
496 {
497   if (hero && hero->getStat(Army::STRENGTH)  > 7)
498     return Army::MOVES;
499   return Army::STRENGTH;
500 }
501
502 bool AI_Smart::chooseQuest(Hero *hero)
503 {
504   return true;
505 }
506 // End of file