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, 2010, 2014, 2015, 2020 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 "citysetlist.h"
36 #include "PathCalculator.h"
37 #include "rnd.h"
38 
39 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
40 #define debug(x)
41 
42 Glib::ustring Citylist::d_tag = "citylist";
43 
44 Citylist* Citylist::s_instance = 0;
45 
getInstance()46 Citylist* Citylist::getInstance()
47 {
48     if (s_instance == 0)
49         s_instance = new Citylist();
50 
51     return s_instance;
52 }
53 
getInstance(XML_Helper * helper)54 Citylist* Citylist::getInstance(XML_Helper* helper)
55 {
56     if (s_instance)
57         deleteInstance();
58 
59     s_instance = new Citylist(helper);
60     return s_instance;
61 }
62 
deleteInstance()63 void Citylist::deleteInstance()
64 {
65     if (s_instance)
66         delete s_instance;
67 
68     s_instance = 0;
69 }
70 
Citylist()71 Citylist::Citylist()
72 {
73 }
74 
Citylist(XML_Helper * helper)75 Citylist::Citylist(XML_Helper* helper)
76 {
77     // simply ask the helper to inform us when a city tag is opened
78     helper->registerTag(City::d_tag, sigc::mem_fun(this, &Citylist::load));
79 }
80 
countCities() const81 int Citylist::countCities() const
82 {
83     int cities = 0;
84 
85     for (const_iterator it = begin(); it != end(); it++)
86     {
87         if ((*it)->isBurnt())
88           continue;
89         cities++;
90     }
91 
92     return cities;
93 }
94 
countCities(Player * player) const95 int Citylist::countCities(Player* player) const
96 {
97     int cities = 0;
98 
99     for (const_iterator it = begin(); it != end(); it++)
100     {
101         if ((*it)->isBurnt())
102           continue;
103         if ((*it)->getOwner() == player) cities++;
104     }
105 
106     return cities;
107 }
108 
collectTaxes(Player * p) const109 void Citylist::collectTaxes(Player* p) const
110 {
111   // Collect the taxes
112   for (const_iterator it = begin(); it != end(); it++)
113     if ((*it)->getOwner() == p && (*it)->isBurnt() == false)
114       p->addGold((*it)->getGold());
115 
116 }
117 
118 //calculate the amount of money new armies will cost in the upcoming turn.
calculateUpcomingUpkeep(Player * p) const119 guint32 Citylist::calculateUpcomingUpkeep(Player *p) const
120 {
121   guint32 total = 0;
122   for (const_iterator it = begin(); it != end(); it++)
123     if ((*it)->getOwner() == p && (*it)->isBurnt() == false)
124       {
125 	if ((*it)->getDuration() == 1)
126 	  {
127 	    int slot =(*it)->getActiveProductionSlot();
128 	    if (slot == -1)
129 	      continue;
130 	    const ArmyProdBase *a = (*it)->getProductionBase(slot);
131 	    total += a->getUpkeep();
132 	    total += a->getProductionCost();
133 	  }
134       }
135   return total;
136 }
137 
nextTurn(Player * p)138 void Citylist::nextTurn(Player* p)
139 {
140     debug("next_turn(" <<p->getName() <<")");
141 
142     // Because players are nextTurn'd before cities, the income, treasury,
143     // and upkeep are calculated already for the upcoming round.
144 
145     //we've already collected taxes this round, so hopefully our
146     //treasury has enough money to pay our city upkeep.
147 
148     guint32 cost_of_new_armies = calculateUpcomingUpkeep(p);
149     if (p->getGold() < (int)cost_of_new_armies)
150       {
151 	int diff = cost_of_new_armies - p->getGold();
152 	//then we have to turn off enough production to make up for diff
153 	//gold pieces.
154 	for (iterator it = begin(); it != end(); it++)
155 	  {
156 	    if ((*it)->isBurnt() == true)
157 	      continue;
158 	    if ((*it)->getOwner() != p)
159 	      continue;
160 	    int slot =(*it)->getActiveProductionSlot();
161 	    if (slot == -1)
162 	      continue;
163 	    const ArmyProdBase *a = (*it)->getProductionBase(slot);
164 	    diff -= a->getUpkeep();
165 
166 	    p->cityTooPoorToProduce((*it), slot);
167 	    if (diff < 0)
168 	      break;
169 	  }
170       }
171 
172     // This iteration adds the city production to the player
173     for (iterator it = begin(); it != end(); it++)
174       {
175         if ((*it)->getOwner() == p)
176             (*it)->nextTurn();
177       }
178 
179 }
180 
isFogged(void * object)181 static bool isFogged(void *object)
182 {
183   return ((City*)object)->isVisible(Playerlist::getViewingplayer()) == false;
184 }
185 
isBurnt(void * object)186 static bool isBurnt(void *object)
187 {
188   return ((City*)object)->isBurnt();
189 }
190 
isNotOwnedByNeutral(void * object)191 static bool isNotOwnedByNeutral(void *object)
192 {
193   return ((City*)object)->getOwner() != Playerlist::getInstance()->getNeutral();
194 }
195 
isNotOwnedByActivePlayer(void * object)196 static bool isNotOwnedByActivePlayer(void *object)
197 {
198   return ((City*)object)->getOwner() != Playerlist::getActiveplayer();
199 }
200 
isOwnedByActivePlayer(void * object)201 static bool isOwnedByActivePlayer(void *object)
202 {
203   return ((City*)object)->getOwner() == Playerlist::getActiveplayer();
204 }
205 
isNotOwnedByEnemy(void * object)206 static bool isNotOwnedByEnemy(void *object)
207 {
208   Player *p = Playerlist::getActiveplayer();
209   if (!p)
210     return false;
211   City *city = ((City*)object);
212   if (city->getOwner() != p &&
213 	    p->getDiplomaticState(city->getOwner()) == Player::AT_WAR)
214     return false;
215   return true;
216 }
217 
canNotAcceptMoreVectoring(void * object)218 static bool canNotAcceptMoreVectoring(void *object)
219 {
220   City *c = ((City*)object);
221   guint32 num = Citylist::getInstance()->countCitiesVectoringTo(c);
222   if (num < MAX_CITIES_VECTORED_TO_ONE_CITY)
223     return false;
224   return true;
225 }
226 
getNearestEnemyCity(const Vector<int> & pos) const227 City* Citylist::getNearestEnemyCity(const Vector<int>& pos) const
228 {
229   std::list<bool (*)(void *)> filters;
230   filters.push_back(isBurnt);
231   filters.push_back(isNotOwnedByEnemy);
232   return getNearestObject(pos, &filters);
233 }
234 
getClosestEnemyCity(const Stack * stack) const235 City* Citylist::getClosestEnemyCity(const Stack *stack) const
236 {
237   std::list<bool (*)(void *)> filters;
238   filters.push_back(isBurnt);
239   filters.push_back(isNotOwnedByEnemy);
240   return getClosestObject(stack, &filters);
241 }
242 
getClosestForeignCity(const Stack * stack) const243 City* Citylist::getClosestForeignCity(const Stack *stack) const
244 {
245   std::list<bool (*)(void *)> filters;
246   filters.push_back(isBurnt);
247   filters.push_back(isOwnedByActivePlayer);
248   return getClosestObject(stack, &filters);
249 }
250 
getNearestForeignCity(const Vector<int> & pos) const251 City* Citylist::getNearestForeignCity(const Vector<int>& pos) const
252 {
253   std::list<bool (*)(void *)> filters;
254   filters.push_back(isBurnt);
255   filters.push_back(isOwnedByActivePlayer);
256   return getNearestObject(pos, &filters);
257 }
258 
getNearestCity(const Vector<int> & pos,int dist) const259 City* Citylist::getNearestCity(const Vector<int>& pos, int dist) const
260 {
261   City *c = getNearestCity(pos);
262   if (!c)
263     return c;
264   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
265       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
266     return c;
267   return NULL;
268 }
269 
getNearestFriendlyCity(const Vector<int> & pos,int dist) const270 City* Citylist::getNearestFriendlyCity(const Vector<int>& pos, int dist) const
271 {
272   City *c = getNearestFriendlyCity(pos);
273   if (!c)
274     return c;
275   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
276       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
277     return c;
278   return NULL;
279 }
280 
getNearestFriendlyCity(const Vector<int> & pos) const281 City* Citylist::getNearestFriendlyCity(const Vector<int>& pos) const
282 {
283     Player* p = Playerlist::getInstance()->getActiveplayer();
284     return getNearestCity (pos, p);
285 }
286 
getNearestCity(const Vector<int> & pos,Player * player) const287 City* Citylist::getNearestCity(const Vector<int>& pos, Player *player) const
288 {
289     int diff = -1;
290     const_iterator diffit;
291 
292     for (const_iterator it = begin(); it != end(); ++it)
293     {
294         if ((*it)->isBurnt())
295             continue;
296 
297         if ((*it)->getOwner() == player)
298         {
299             Vector<int> p = (*it)->getPos();
300             int delta = abs(p.x - pos.x);
301             if (delta < abs(p.y - pos.y))
302                 delta = abs(p.y - pos.y);
303 
304             if ((diff > delta) || (diff == -1))
305             {
306                 diff = delta;
307                 diffit = it;
308             }
309         }
310     }
311 
312     if (diff == -1) return 0;
313     return (*diffit);
314 }
315 
getClosestCity(const Stack * stack,Player * p) const316 City* Citylist::getClosestCity(const Stack *stack, Player *p) const
317 {
318     int diff = -1;
319     const_iterator diffit;
320     PathCalculator pc(stack, true, 0, 0);
321 
322     for (const_iterator it = begin(); it != end(); ++it)
323     {
324         if ((*it)->isBurnt())
325             continue;
326 
327         if ((*it)->getOwner() == p)
328         {
329             int delta = pc.calculate((*it)->getPos());
330             if (delta <= 0)
331               continue;
332 
333             if ((diff > delta) || (diff == -1))
334             {
335                 diff = delta;
336                 diffit = it;
337             }
338         }
339     }
340 
341     if (diff == -1) return 0;
342     return (*diffit);
343 }
344 
getClosestFriendlyCity(const Stack * stack) const345 City* Citylist::getClosestFriendlyCity(const Stack *stack) const
346 {
347     Player* p = Playerlist::getInstance()->getActiveplayer();
348     return getClosestCity (stack, p);
349 }
getClosestCity(const Stack * stack) const350 City* Citylist::getClosestCity(const Stack *stack) const
351 {
352   std::list<bool (*)(void *)> filters;
353   filters.push_back(isBurnt);
354   return getClosestObject(stack, &filters);
355 }
356 
getNearestCity(const Vector<int> & pos) const357 City* Citylist::getNearestCity(const Vector<int>& pos) const
358 {
359   std::list<bool (*)(void *)> filters;
360   filters.push_back(isBurnt);
361   return getNearestObject(pos, &filters);
362 }
363 
getNearestVisibleCity(const Vector<int> & pos) const364 City* Citylist::getNearestVisibleCity(const Vector<int>& pos) const
365 {
366   std::list<bool (*)(void *)> filters;
367   filters.push_back(isBurnt);
368   filters.push_back(isFogged);
369   return getNearestObject(pos, &filters);
370 }
371 
getNearestVisibleCity(const Vector<int> & pos,int dist) const372 City* Citylist::getNearestVisibleCity(const Vector<int>& pos, int dist) const
373 {
374   City *c = getNearestVisibleCity(pos);
375   if (!c)
376     return c;
377   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
378       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
379     return c;
380   return NULL;
381 }
382 
getNearestVisibleFriendlyCity(const Vector<int> & pos,int dist) const383 City* Citylist::getNearestVisibleFriendlyCity(const Vector<int>& pos, int dist) const
384 {
385   City *c = getNearestFriendlyCity(pos);
386   if (!c)
387     return c;
388   if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
389       c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
390     return c;
391   return NULL;
392 }
393 
394 
getNearestVisibleFriendlyCity(const Vector<int> & pos) const395 City* Citylist::getNearestVisibleFriendlyCity(const Vector<int>& pos) const
396 {
397   std::list<bool (*)(void *)> filters;
398   filters.push_back(isBurnt);
399   filters.push_back(isFogged);
400   filters.push_back(isNotOwnedByActivePlayer);
401   return getNearestObject(pos, &filters);
402 }
403 
getNearestNeutralCity(const Vector<int> & pos) const404 City* Citylist::getNearestNeutralCity(const Vector<int>& pos) const
405 {
406   std::list<bool (*)(void *)> filters;
407   filters.push_back(isBurnt);
408   filters.push_back(isNotOwnedByNeutral);
409   return getNearestObject(pos, &filters);
410 }
411 
getNearestFriendlyVectorableCity(const Vector<int> & pos) const412 City* Citylist::getNearestFriendlyVectorableCity(const Vector<int>& pos) const
413 {
414   std::list<bool (*)(void *)> filters;
415   filters.push_back(isBurnt);
416   filters.push_back(isNotOwnedByActivePlayer);
417   filters.push_back(canNotAcceptMoreVectoring);
418   return getNearestObject(pos, &filters);
419 }
420 
save(XML_Helper * helper) const421 bool Citylist::save(XML_Helper* helper) const
422 {
423     bool retval = true;
424 
425     retval &= helper->openTag(Citylist::d_tag);
426 
427     for (const_iterator it = begin(); it != end(); it++)
428         (*it)->save(helper);
429 
430     retval &= helper->closeTag();
431 
432     return retval;
433 }
434 
load(Glib::ustring tag,XML_Helper * helper)435 bool Citylist::load(Glib::ustring tag, XML_Helper* helper)
436 {
437     if (tag == City::d_tag)
438       {
439         Cityset *cs = GameMap::getCityset();
440 	City *c = new City(helper, cs->getCityTileWidth());
441 	add(c);
442 	return true;
443       }
444     return false;
445 }
446 
changeOwnership(Player * old_owner,Player * new_owner)447 void Citylist::changeOwnership(Player *old_owner, Player *new_owner)
448 {
449   for (iterator it = begin(); it != end(); it++)
450     if ((*it)->getOwner() == old_owner)
451       {
452         stopVectoringTo(*it);
453         (*it)->setVectoring(Vector<int>(-1,-1));
454 	(*it)->setOwner(new_owner);
455 	if ((*it)->isCapital())
456 	  if ((*it)->getCapitalOwner() == old_owner)
457 	    (*it)->setCapitalOwner(new_owner);
458         if (new_owner == Playerlist::getInstance()->getNeutral())
459           (*it)->setActiveProductionSlot(-1); //hmm, what about neutral policy.
460       }
461 }
462 
stopVectoringTo(City * c)463 void Citylist::stopVectoringTo(City *c)
464 {
465   for (iterator it = begin(); it != end(); it++)
466     {
467       if ((*it)->isBurnt() == true)
468 	continue;
469       if ((*it)->getVectoring() == Vector<int>(-1,-1))
470 	continue;
471       if (c->contains((*it)->getVectoring()))
472 	(*it)->setVectoring(Vector<int>(-1,-1));
473     }
474   return;
475 }
476 
isVectoringTarget(City * target) const477 bool Citylist::isVectoringTarget(City *target) const
478 {
479   for (const_iterator it = begin(); it != end(); it++)
480     {
481       if ((*it)->getOwner() != target->getOwner())
482 	continue;
483       if (target->contains((*it)->getVectoring()))
484 	return true;
485     }
486   return false;
487 }
488 
getCitiesVectoringTo(Vector<int> target) const489 std::list<City*> Citylist::getCitiesVectoringTo(Vector<int> target) const
490 {
491   std::list<City*> cities;
492   for (const_iterator it = begin(); it != end(); it++)
493     {
494       if (target == (*it)->getVectoring())
495 	cities.push_back((*it));
496     }
497   return cities;
498 }
499 
getCitiesVectoringTo(City * target) const500 std::list<City*> Citylist::getCitiesVectoringTo(City *target) const
501 {
502   std::list<City*> cities;
503   for (const_iterator it = begin(); it != end(); it++)
504     {
505       if ((*it)->getOwner() != target->getOwner())
506 	continue;
507       if (target->contains((*it)->getVectoring()))
508 	cities.push_back((*it));
509     }
510   return cities;
511 }
512 
getNearestCityPast(const Vector<int> & pos,int dist) const513 City* Citylist::getNearestCityPast(const Vector<int>& pos, int dist) const
514 {
515   std::list<bool (*)(void *)> filters;
516   filters.push_back(isBurnt);
517   return getNearestObjectAfter(pos, dist, &filters);
518 }
519 
countCitiesVectoringTo(const City * dest) const520 guint32 Citylist::countCitiesVectoringTo(const City *dest) const
521 {
522   guint32 count = 0;
523   for (const_iterator it = begin(); it != end(); it++)
524     {
525       City *c = *it;
526       if (c->getOwner() != dest->getOwner())
527 	continue;
528       if (c->getVectoring() == dest->getPos())
529 	count++;
530     }
531 
532   return count;
533 }
534 
getNearestFriendlyCities(Player * player,Vector<int> pos) const535 std::list<City*> Citylist::getNearestFriendlyCities(Player *player, Vector<int> pos) const
536 {
537   std::list<City*> cities;
538   for (const_iterator it = begin(); it != end(); it++)
539     {
540       City *c = *it;
541       if (c->getOwner() != player)
542         continue;
543       if (c->isBurnt() == true)
544         continue;
545       cities.push_back(c);
546     }
547   if (cities.size() == 0)
548     return cities;
549   std::list<int> distances;
550 
551   if (pos == Vector<int>(-1,-1))
552     pos = player->getFirstCity()->getPos();
553 
554   for (std::list<City*>::iterator it = cities.begin(); it != cities.end(); it++)
555     distances.push_back(dist((*it)->getNearestPos(pos), pos));
556 
557   bool sorted = false;
558 
559   while (!sorted)
560     {
561       sorted = true;
562 
563       // setup
564       std::list<int>::iterator dit = distances.begin();
565       std::list<int>::iterator dnextit = distances.begin();
566       dnextit++;
567 
568       std::list<City*>::iterator it = cities.begin();
569       std::list<City*>::iterator nextit = it;
570       nextit++;
571 
572       for (; nextit != cities.end(); it++, nextit++, dit++, dnextit++)
573         if ((*dit) > (*dnextit))
574           {
575             // exchange the items in both lists
576             sorted = false;
577 
578             City* tmp = (*nextit);
579             cities.erase(nextit);
580             nextit = it;
581             it = cities.insert(nextit, tmp);
582 
583             int val = (*dnextit);
584             distances.erase(dnextit);
585             dnextit = dit;
586             dit = distances.insert(dnextit, val);
587           }
588     }
589   return cities;
590 }
591 
getCapitalCity(Player * player) const592 City *Citylist::getCapitalCity(Player *player) const
593 {
594   for (const_iterator it = begin(); it != end(); it++)
595     {
596       City *c = *it;
597       if (c->isCapital() && c->getCapitalOwner() &&
598           c->getCapitalOwner()->getId() == player->getId())
599         return c;
600     }
601   return NULL;
602 }
603 
getRandomCityForHero(Player * player) const604 City *Citylist::getRandomCityForHero(Player *player) const
605 {
606   std::vector<City*> cities;
607   for (const_iterator it = begin(); it != end(); it++)
608     if (!(*it)->isBurnt() && (*it)->getOwner() == player)
609       cities.push_back((*it));
610   if (cities.empty())
611     return NULL;
612   return cities[Rnd::rand() % cities.size()];
613 }
614 
countUnamedCities() const615 guint32 Citylist::countUnamedCities () const
616 {
617   guint32 count = 0;
618   for (const_iterator it = begin(); it != end(); it++)
619     if ((*it)->getName () == DEFAULT_CITY_NAME)
620       count++;
621   return count;
622 }
623 // End of file
624