initial commit, lordsawar source, slightly modified
[lordsawar] / src / citylist.cpp
1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005 Ulf Lorenz
3 // Copyright (C) 2004 John Farrell
4 // Copyright (C) 2005 Andrea Paternesi
5 // Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
6 // Copyright (C) 2007 Ole Laursen
7 //
8 //  This program is free software; you can redistribute it and/or modify
9 //  it under the terms of the GNU General Public License as published by
10 //  the Free Software Foundation; either version 3 of the License, or
11 //  (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU Library General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
21 //  02110-1301, USA.
22
23 #include <sigc++/functors/mem_fun.h>
24
25 #include "citylist.h"
26 #include "city.h"
27 #include "playerlist.h"
28 #include <limits.h>
29 #include "xmlhelper.h"
30 #include "hero.h"
31 #include "stack.h"
32 #include "armyprodbase.h"
33 #include "GameMap.h"
34 #include "cityset.h"
35 #include "PathCalculator.h"
36
37 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
38 #define debug(x)
39
40 std::string Citylist::d_tag = "citylist";
41
42 Citylist* Citylist::s_instance = 0;
43
44 Citylist* Citylist::getInstance()
45 {
46     if (s_instance == 0)
47         s_instance = new Citylist();
48
49     return s_instance;
50 }
51
52 Citylist* Citylist::getInstance(XML_Helper* helper)
53 {
54     if (s_instance)
55         deleteInstance();
56
57     s_instance = new Citylist(helper);
58     return s_instance;
59 }
60
61 void Citylist::deleteInstance()
62 {
63     if (s_instance)
64         delete s_instance;
65
66     s_instance = 0;
67 }
68
69 Citylist::Citylist()
70 {
71 }
72
73 Citylist::Citylist(XML_Helper* helper)
74 {
75     // simply ask the helper to inform us when a city tag is opened
76     helper->registerTag(City::d_tag, sigc::mem_fun(this, &Citylist::load));
77 }
78
79 Citylist::~Citylist()
80 {
81 }
82
83 int Citylist::countCities() const
84 {
85     int cities = 0;
86     
87     for (const_iterator it = begin(); it != end(); it++)
88     {
89         if ((*it)->isBurnt())
90           continue;
91         cities++;
92     }
93     
94     return cities;
95 }
96
97 int Citylist::countCities(Player* player) const
98 {
99     int cities = 0;
100     
101     for (const_iterator it = begin(); it != end(); it++)
102     {
103         if ((*it)->isBurnt())
104           continue;
105         if ((*it)->getOwner() == player) cities++;
106     }
107     
108     return cities;
109 }
110
111 void Citylist::collectTaxes(Player* p) const
112 {
113   // Collect the taxes
114   for (const_iterator it = begin(); it != end(); it++)
115     if ((*it)->getOwner() == p && (*it)->isBurnt() == false)
116       p->addGold((*it)->getGold());
117
118 }
119
120 //calculate the amount of money new armies will cost in the upcoming turn.
121 guint32 Citylist::calculateUpcomingUpkeep(Player *p) const
122 {
123   guint32 total = 0;
124   for (const_iterator it = begin(); it != end(); it++)
125     if ((*it)->getOwner() == p && (*it)->isBurnt() == false)
126       {
127         if ((*it)->getDuration() == 1)
128           {
129             int slot =(*it)->getActiveProductionSlot();
130             if (slot == -1)
131               continue;
132             const ArmyProdBase *a = (*it)->getProductionBase(slot);
133             total += a->getUpkeep();
134             total += a->getProductionCost();
135           }
136       }
137   return total;
138 }
139
140 void Citylist::nextTurn(Player* p)
141 {
142     debug("next_turn(" <<p->getName() <<")");
143
144     // Because players are nextTurn'd before cities, the income, treasury, 
145     // and upkeep are calculated already for the upcoming round.
146
147     //we've already collected taxes this round, so hopefully our
148     //treasury has enough money to pay our city upkeep.
149
150     guint32 cost_of_new_armies = calculateUpcomingUpkeep(p);
151     if (p->getGold() < (int)cost_of_new_armies)
152       {
153         int diff = cost_of_new_armies - p->getGold();
154         //then we have to turn off enough production to make up for diff
155         //gold pieces.
156         for (iterator it = begin(); it != end(); it++)
157           {
158             if ((*it)->isBurnt() == true)
159               continue;
160             if ((*it)->getOwner() != p)
161               continue;
162             int slot =(*it)->getActiveProductionSlot();
163             if (slot == -1)
164               continue;
165             const ArmyProdBase *a = (*it)->getProductionBase(slot);
166             diff -= a->getUpkeep();
167     
168             p->cityTooPoorToProduce((*it), slot);
169             if (diff < 0)
170               break;
171           }
172       }
173
174     // This iteration adds the city production to the player    
175     for (iterator it = begin(); it != end(); it++)
176       {
177         if ((*it)->getOwner() == p)
178             (*it)->nextTurn();
179       }
180
181 }
182
183 static bool isFogged(void *object)
184 {
185   return ((City*)object)->isVisible(Playerlist::getViewingplayer()) == false;
186 }
187
188 static bool isBurnt(void *object)
189 {
190   return ((City*)object)->isBurnt();
191 }
192
193 static bool isNotOwnedByNeutral(void *object)
194 {
195   return ((City*)object)->getOwner() != Playerlist::getInstance()->getNeutral();
196 }
197
198 static bool isNotOwnedByActivePlayer(void *object)
199 {
200   return ((City*)object)->getOwner() != Playerlist::getActiveplayer();
201 }
202
203 static bool isOwnedByActivePlayer(void *object)
204 {
205   return ((City*)object)->getOwner() == Playerlist::getActiveplayer();
206 }
207
208 static bool isNotOwnedByEnemy(void *object)
209 {
210   Player *p = Playerlist::getActiveplayer();
211   if (!p)
212     return false;
213   City *city = ((City*)object);
214   if (city->getOwner() != p &&
215             p->getDiplomaticState(city->getOwner()) == Player::AT_WAR)
216     return false;
217   return true;
218 }
219
220 static bool canNotAcceptMoreVectoring(void *object)
221 {
222   City *c = ((City*)object);
223   guint32 num = Citylist::getInstance()->countCitiesVectoringTo(c);
224   if (num < MAX_CITIES_VECTORED_TO_ONE_CITY)
225     return false;
226   return true;
227 }
228
229 City* Citylist::getNearestEnemyCity(const Vector<int>& pos) const
230 {
231   std::list<bool (*)(void *)> filters;
232   filters.push_back(isBurnt);
233   filters.push_back(isNotOwnedByEnemy);
234   return getNearestObject(pos, &filters);
235 }
236
237 City* Citylist::getClosestEnemyCity(const Stack *stack) const
238 {
239   std::list<bool (*)(void *)> filters;
240   filters.push_back(isBurnt);
241   filters.push_back(isNotOwnedByEnemy);
242   return getClosestObject(stack, &filters);
243 }
244
245 City* Citylist::getClosestForeignCity(const Stack *stack) const
246 {
247   std::list<bool (*)(void *)> filters;
248   filters.push_back(isBurnt);
249   filters.push_back(isOwnedByActivePlayer);
250   return getClosestObject(stack, &filters);
251 }
252
253 City* Citylist::getNearestForeignCity(const Vector<int>& pos) const
254 {
255   std::list<bool (*)(void *)> filters;
256   filters.push_back(isBurnt);
257   filters.push_back(isOwnedByActivePlayer);
258   return getNearestObject(pos, &filters);
259 }
260
261 City* Citylist::getNearestCity(const Vector<int>& pos, int dist) const
262 {
263   City *c = getNearestCity(pos);
264   if (!c)
265     return c;
266   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
267       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
268     return c;
269   return NULL;
270 }
271
272 City* Citylist::getNearestFriendlyCity(const Vector<int>& pos, int dist) const 
273 {
274   City *c = getNearestFriendlyCity(pos);
275   if (!c)
276     return c;
277   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
278       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
279     return c;
280   return NULL;
281 }
282
283 City* Citylist::getNearestFriendlyCity(const Vector<int>& pos) const
284 {
285     Player* p = Playerlist::getInstance()->getActiveplayer();
286     return getNearestCity (pos, p);
287 }
288
289 City* Citylist::getNearestCity(const Vector<int>& pos, Player *p) const
290 {
291     int diff = -1;
292     const_iterator diffit;
293     
294     for (const_iterator it = begin(); it != end(); ++it)
295     {
296         if ((*it)->isBurnt())
297             continue;
298
299         if ((*it)->getOwner() == p)
300         {
301             Vector<int> p = (*it)->getPos();
302             int delta = abs(p.x - pos.x);
303             if (delta < abs(p.y - pos.y))
304                 delta = abs(p.y - pos.y);
305             
306             if ((diff > delta) || (diff == -1))
307             {
308                 diff = delta;
309                 diffit = it;
310             }
311         }
312     }
313     
314     if (diff == -1) return 0;
315     return (*diffit);
316 }
317
318 City* Citylist::getClosestCity(const Stack *stack, Player *p) const
319 {
320     int diff = -1;
321     const_iterator diffit;
322     PathCalculator pc(stack, true, 0, 0);
323     
324     for (const_iterator it = begin(); it != end(); ++it)
325     {
326         if ((*it)->isBurnt())
327             continue;
328
329         if ((*it)->getOwner() == p)
330         {
331             int delta = pc.calculate((*it)->getPos());
332             if (delta <= 0)
333               continue;
334             
335             if ((diff > delta) || (diff == -1))
336             {
337                 diff = delta;
338                 diffit = it;
339             }
340         }
341     }
342     
343     if (diff == -1) return 0;
344     return (*diffit);
345 }
346
347 City* Citylist::getClosestFriendlyCity(const Stack *stack) const
348 {
349     Player* p = Playerlist::getInstance()->getActiveplayer();
350     return getClosestCity (stack, p);
351 }
352 City* Citylist::getClosestCity(const Stack *stack) const
353 {
354   std::list<bool (*)(void *)> filters;
355   filters.push_back(isBurnt);
356   return getClosestObject(stack, &filters);
357 }
358
359 City* Citylist::getNearestCity(const Vector<int>& pos) const
360 {
361   std::list<bool (*)(void *)> filters;
362   filters.push_back(isBurnt);
363   return getNearestObject(pos, &filters);
364 }
365
366 City* Citylist::getNearestVisibleCity(const Vector<int>& pos) const
367 {
368   std::list<bool (*)(void *)> filters;
369   filters.push_back(isBurnt);
370   filters.push_back(isFogged);
371   return getNearestObject(pos, &filters);
372 }
373
374 City* Citylist::getNearestVisibleCity(const Vector<int>& pos, int dist) const
375 {
376   City *c = getNearestVisibleCity(pos);
377   if (!c)
378     return c;
379   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
380       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
381     return c;
382   return NULL;
383 }
384
385 City* Citylist::getNearestVisibleFriendlyCity(const Vector<int>& pos, int dist) const
386 {
387   City *c = getNearestFriendlyCity(pos);
388   if (!c)
389     return c;
390   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
391       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
392     return c;
393   return NULL;
394 }
395
396
397 City* Citylist::getNearestVisibleFriendlyCity(const Vector<int>& pos) const
398 {
399   std::list<bool (*)(void *)> filters;
400   filters.push_back(isBurnt);
401   filters.push_back(isFogged);
402   filters.push_back(isNotOwnedByActivePlayer);
403   return getNearestObject(pos, &filters);
404 }
405
406 City* Citylist::getNearestNeutralCity(const Vector<int>& pos) const
407 {
408   std::list<bool (*)(void *)> filters;
409   filters.push_back(isBurnt);
410   filters.push_back(isNotOwnedByNeutral);
411   return getNearestObject(pos, &filters);
412 }
413
414 City* Citylist::getNearestFriendlyVectorableCity(const Vector<int>& pos) const
415 {
416   std::list<bool (*)(void *)> filters;
417   filters.push_back(isBurnt);
418   filters.push_back(isNotOwnedByActivePlayer);
419   filters.push_back(canNotAcceptMoreVectoring);
420   return getNearestObject(pos, &filters);
421 }
422
423 City* Citylist::getFirstCity(Player* p) const
424 {
425     for (const_iterator it = begin(); it != end(); it++)
426         if ((*it)->getOwner() == p)
427             return (*it);
428
429     return 0;
430 }
431
432 bool Citylist::save(XML_Helper* helper) const
433 {
434     bool retval = true;
435
436     retval &= helper->openTag(Citylist::d_tag);
437
438     for (const_iterator it = begin(); it != end(); it++)
439         (*it)->save(helper);
440     
441     retval &= helper->closeTag();
442
443     return retval;
444 }
445
446 bool Citylist::load(std::string tag, XML_Helper* helper)
447 {
448     if (tag == City::d_tag)
449       {
450         Cityset *cs = GameMap::getInstance()->getCityset();
451         City *c = new City(helper, cs->getCityTileWidth());
452         add(c);
453         return true;
454       }
455     return false;
456 }
457
458 void Citylist::changeOwnership(Player *old_owner, Player *new_owner)
459 {
460   for (iterator it = begin(); it != end(); it++)
461     if ((*it)->getOwner() == old_owner)
462       {
463         (*it)->setOwner(new_owner);
464         if ((*it)->isCapital())
465           if ((*it)->getCapitalOwner() == old_owner)
466             (*it)->setCapitalOwner(new_owner);
467       }
468 }
469
470 void Citylist::stopVectoringTo(City *c)
471 {
472   for (iterator it = begin(); it != end(); it++)
473     {
474       if ((*it)->isBurnt() == true)
475         continue;
476       if ((*it)->getVectoring() == Vector<int>(-1,-1))
477         continue;
478       if (c->contains((*it)->getVectoring()))
479         (*it)->setVectoring(Vector<int>(-1,-1));
480     }
481   return;
482 }
483
484 bool Citylist::isVectoringTarget(City *target) const
485 {
486   for (const_iterator it = begin(); it != end(); it++)
487     {
488       if ((*it)->getOwner() != target->getOwner())
489         continue;
490       if (target->contains((*it)->getVectoring()))
491         return true;
492     }
493   return false;
494 }
495
496 std::list<City*> Citylist::getCitiesVectoringTo(Vector<int> target) const
497 {
498   std::list<City*> cities;
499   for (const_iterator it = begin(); it != end(); it++)
500     {
501       if (target == (*it)->getVectoring())
502         cities.push_back((*it));
503     }
504   return cities;
505 }
506
507 std::list<City*> Citylist::getCitiesVectoringTo(City *target) const
508 {
509   std::list<City*> cities;
510   for (const_iterator it = begin(); it != end(); it++)
511     {
512       if ((*it)->getOwner() != target->getOwner())
513         continue;
514       if (target->contains((*it)->getVectoring()))
515         cities.push_back((*it));
516     }
517   return cities;
518 }
519
520 City* Citylist::getNearestCityPast(const Vector<int>& pos, int dist) const
521 {
522   std::list<bool (*)(void *)> filters;
523   filters.push_back(isBurnt);
524   return getNearestObjectAfter(pos, dist, &filters);
525 }
526
527 guint32 Citylist::countCitiesVectoringTo(const City *dest) const
528 {
529   guint32 count = 0;
530   for (const_iterator it = begin(); it != end(); it++)
531     {
532       City *c = *it;
533       if (c->getOwner() != dest->getOwner())
534         continue;
535       if (c->getVectoring() == dest->getPos())
536         count++;
537     }
538
539   return count;
540 }
541
542 std::list<City*> Citylist::getNearestFriendlyCities(Player *player, Vector<int> pos) const
543 {
544   std::list<City*> cities;
545   for (const_iterator it = begin(); it != end(); it++)
546     {
547       City *c = *it;
548       if (c->getOwner() != player)
549         continue;
550       if (c->isBurnt() == true)
551         continue;
552       cities.push_back(c);
553     }
554   if (cities.size() == 0)
555     return cities;
556   std::list<int> distances;
557
558   if (pos == Vector<int>(-1,-1))
559     pos = getFirstCity(player)->getPos();
560
561   for (std::list<City*>::iterator it = cities.begin(); it != cities.end(); it++)
562     distances.push_back(dist((*it)->getNearestPos(pos), pos));
563
564   bool sorted = false;
565
566   while (!sorted)
567     {
568       sorted = true;
569
570       // setup
571       std::list<int>::iterator dit = distances.begin();
572       std::list<int>::iterator dnextit = distances.begin();
573       dnextit++;
574
575       std::list<City*>::iterator it = cities.begin();
576       std::list<City*>::iterator nextit = it;
577       nextit++;
578
579       for (; nextit != cities.end(); it++, nextit++, dit++, dnextit++)
580         if ((*dit) > (*dnextit))
581           {
582             // exchange the items in both lists
583             sorted = false;
584
585             City* tmp = (*nextit);
586             cities.erase(nextit);
587             nextit = it;
588             it = cities.insert(nextit, tmp);
589
590             int val = (*dnextit);
591             distances.erase(dnextit);
592             dnextit = dit;
593             dit = distances.insert(dnextit, val);
594           }
595     }
596   return cities;
597 }
598
599 City *Citylist::getCapitalCity(Player *player) const
600 {
601   for (const_iterator it = begin(); it != end(); it++)
602     {
603       City *c = *it;
604       if (c->getCapitalOwner() == player)
605         return c;
606     }
607   return NULL;
608 }
609 // End of file