initial commit, lordsawar source, slightly modified
[lordsawar] / src / citylist.cpp
diff --git a/src/citylist.cpp b/src/citylist.cpp
new file mode 100644 (file)
index 0000000..7f79130
--- /dev/null
@@ -0,0 +1,609 @@
+// Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
+// Copyright (C) 2001, 2002, 2003, 2004, 2005 Ulf Lorenz
+// Copyright (C) 2004 John Farrell
+// Copyright (C) 2005 Andrea Paternesi
+// Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
+// Copyright (C) 2007 Ole Laursen
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU Library General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+//  02110-1301, USA.
+
+#include <sigc++/functors/mem_fun.h>
+
+#include "citylist.h"
+#include "city.h"
+#include "playerlist.h"
+#include <limits.h>
+#include "xmlhelper.h"
+#include "hero.h"
+#include "stack.h"
+#include "armyprodbase.h"
+#include "GameMap.h"
+#include "cityset.h"
+#include "PathCalculator.h"
+
+//#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
+#define debug(x)
+
+std::string Citylist::d_tag = "citylist";
+
+Citylist* Citylist::s_instance = 0;
+
+Citylist* Citylist::getInstance()
+{
+    if (s_instance == 0)
+        s_instance = new Citylist();
+
+    return s_instance;
+}
+
+Citylist* Citylist::getInstance(XML_Helper* helper)
+{
+    if (s_instance)
+        deleteInstance();
+
+    s_instance = new Citylist(helper);
+    return s_instance;
+}
+
+void Citylist::deleteInstance()
+{
+    if (s_instance)
+        delete s_instance;
+
+    s_instance = 0;
+}
+
+Citylist::Citylist()
+{
+}
+
+Citylist::Citylist(XML_Helper* helper)
+{
+    // simply ask the helper to inform us when a city tag is opened
+    helper->registerTag(City::d_tag, sigc::mem_fun(this, &Citylist::load));
+}
+
+Citylist::~Citylist()
+{
+}
+
+int Citylist::countCities() const
+{
+    int cities = 0;
+    
+    for (const_iterator it = begin(); it != end(); it++)
+    {
+        if ((*it)->isBurnt())
+          continue;
+        cities++;
+    }
+    
+    return cities;
+}
+
+int Citylist::countCities(Player* player) const
+{
+    int cities = 0;
+    
+    for (const_iterator it = begin(); it != end(); it++)
+    {
+        if ((*it)->isBurnt())
+          continue;
+        if ((*it)->getOwner() == player) cities++;
+    }
+    
+    return cities;
+}
+
+void Citylist::collectTaxes(Player* p) const
+{
+  // Collect the taxes
+  for (const_iterator it = begin(); it != end(); it++)
+    if ((*it)->getOwner() == p && (*it)->isBurnt() == false)
+      p->addGold((*it)->getGold());
+
+}
+
+//calculate the amount of money new armies will cost in the upcoming turn.
+guint32 Citylist::calculateUpcomingUpkeep(Player *p) const
+{
+  guint32 total = 0;
+  for (const_iterator it = begin(); it != end(); it++)
+    if ((*it)->getOwner() == p && (*it)->isBurnt() == false)
+      {
+       if ((*it)->getDuration() == 1)
+         {
+           int slot =(*it)->getActiveProductionSlot();
+           if (slot == -1)
+             continue;
+           const ArmyProdBase *a = (*it)->getProductionBase(slot);
+           total += a->getUpkeep();
+           total += a->getProductionCost();
+         }
+      }
+  return total;
+}
+
+void Citylist::nextTurn(Player* p)
+{
+    debug("next_turn(" <<p->getName() <<")");
+
+    // Because players are nextTurn'd before cities, the income, treasury, 
+    // and upkeep are calculated already for the upcoming round.
+
+    //we've already collected taxes this round, so hopefully our
+    //treasury has enough money to pay our city upkeep.
+
+    guint32 cost_of_new_armies = calculateUpcomingUpkeep(p);
+    if (p->getGold() < (int)cost_of_new_armies)
+      {
+       int diff = cost_of_new_armies - p->getGold();
+       //then we have to turn off enough production to make up for diff
+       //gold pieces.
+       for (iterator it = begin(); it != end(); it++)
+         {
+           if ((*it)->isBurnt() == true)
+             continue;
+           if ((*it)->getOwner() != p)
+             continue;
+           int slot =(*it)->getActiveProductionSlot();
+           if (slot == -1)
+             continue;
+           const ArmyProdBase *a = (*it)->getProductionBase(slot);
+           diff -= a->getUpkeep();
+    
+           p->cityTooPoorToProduce((*it), slot);
+           if (diff < 0)
+             break;
+         }
+      }
+
+    // This iteration adds the city production to the player    
+    for (iterator it = begin(); it != end(); it++)
+      {
+        if ((*it)->getOwner() == p)
+            (*it)->nextTurn();
+      }
+
+}
+
+static bool isFogged(void *object)
+{
+  return ((City*)object)->isVisible(Playerlist::getViewingplayer()) == false;
+}
+
+static bool isBurnt(void *object)
+{
+  return ((City*)object)->isBurnt();
+}
+
+static bool isNotOwnedByNeutral(void *object)
+{
+  return ((City*)object)->getOwner() != Playerlist::getInstance()->getNeutral();
+}
+
+static bool isNotOwnedByActivePlayer(void *object)
+{
+  return ((City*)object)->getOwner() != Playerlist::getActiveplayer();
+}
+
+static bool isOwnedByActivePlayer(void *object)
+{
+  return ((City*)object)->getOwner() == Playerlist::getActiveplayer();
+}
+
+static bool isNotOwnedByEnemy(void *object)
+{
+  Player *p = Playerlist::getActiveplayer();
+  if (!p)
+    return false;
+  City *city = ((City*)object);
+  if (city->getOwner() != p &&
+           p->getDiplomaticState(city->getOwner()) == Player::AT_WAR)
+    return false;
+  return true;
+}
+
+static bool canNotAcceptMoreVectoring(void *object)
+{
+  City *c = ((City*)object);
+  guint32 num = Citylist::getInstance()->countCitiesVectoringTo(c);
+  if (num < MAX_CITIES_VECTORED_TO_ONE_CITY)
+    return false;
+  return true;
+}
+
+City* Citylist::getNearestEnemyCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isNotOwnedByEnemy);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getClosestEnemyCity(const Stack *stack) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isNotOwnedByEnemy);
+  return getClosestObject(stack, &filters);
+}
+
+City* Citylist::getClosestForeignCity(const Stack *stack) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isOwnedByActivePlayer);
+  return getClosestObject(stack, &filters);
+}
+
+City* Citylist::getNearestForeignCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isOwnedByActivePlayer);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getNearestCity(const Vector<int>& pos, int dist) const
+{
+  City *c = getNearestCity(pos);
+  if (!c)
+    return c;
+  if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
+      c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
+    return c;
+  return NULL;
+}
+
+City* Citylist::getNearestFriendlyCity(const Vector<int>& pos, int dist) const 
+{
+  City *c = getNearestFriendlyCity(pos);
+  if (!c)
+    return c;
+  if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
+      c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
+    return c;
+  return NULL;
+}
+
+City* Citylist::getNearestFriendlyCity(const Vector<int>& pos) const
+{
+    Player* p = Playerlist::getInstance()->getActiveplayer();
+    return getNearestCity (pos, p);
+}
+
+City* Citylist::getNearestCity(const Vector<int>& pos, Player *p) const
+{
+    int diff = -1;
+    const_iterator diffit;
+    
+    for (const_iterator it = begin(); it != end(); ++it)
+    {
+        if ((*it)->isBurnt())
+            continue;
+
+        if ((*it)->getOwner() == p)
+        {
+            Vector<int> p = (*it)->getPos();
+            int delta = abs(p.x - pos.x);
+            if (delta < abs(p.y - pos.y))
+                delta = abs(p.y - pos.y);
+            
+            if ((diff > delta) || (diff == -1))
+            {
+                diff = delta;
+                diffit = it;
+            }
+        }
+    }
+    
+    if (diff == -1) return 0;
+    return (*diffit);
+}
+
+City* Citylist::getClosestCity(const Stack *stack, Player *p) const
+{
+    int diff = -1;
+    const_iterator diffit;
+    PathCalculator pc(stack, true, 0, 0);
+    
+    for (const_iterator it = begin(); it != end(); ++it)
+    {
+        if ((*it)->isBurnt())
+            continue;
+
+        if ((*it)->getOwner() == p)
+        {
+            int delta = pc.calculate((*it)->getPos());
+            if (delta <= 0)
+              continue;
+            
+            if ((diff > delta) || (diff == -1))
+            {
+                diff = delta;
+                diffit = it;
+            }
+        }
+    }
+    
+    if (diff == -1) return 0;
+    return (*diffit);
+}
+
+City* Citylist::getClosestFriendlyCity(const Stack *stack) const
+{
+    Player* p = Playerlist::getInstance()->getActiveplayer();
+    return getClosestCity (stack, p);
+}
+City* Citylist::getClosestCity(const Stack *stack) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  return getClosestObject(stack, &filters);
+}
+
+City* Citylist::getNearestCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getNearestVisibleCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isFogged);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getNearestVisibleCity(const Vector<int>& pos, int dist) const
+{
+  City *c = getNearestVisibleCity(pos);
+  if (!c)
+    return c;
+  if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
+      c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
+    return c;
+  return NULL;
+}
+
+City* Citylist::getNearestVisibleFriendlyCity(const Vector<int>& pos, int dist) const
+{
+  City *c = getNearestFriendlyCity(pos);
+  if (!c)
+    return c;
+  if (c->getPos().x <= pos.x + dist && c->getPos().x >= pos.x - dist &&
+      c->getPos().y <= pos.y + dist && c->getPos().y >= pos.y - dist)
+    return c;
+  return NULL;
+}
+
+
+City* Citylist::getNearestVisibleFriendlyCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isFogged);
+  filters.push_back(isNotOwnedByActivePlayer);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getNearestNeutralCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isNotOwnedByNeutral);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getNearestFriendlyVectorableCity(const Vector<int>& pos) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  filters.push_back(isNotOwnedByActivePlayer);
+  filters.push_back(canNotAcceptMoreVectoring);
+  return getNearestObject(pos, &filters);
+}
+
+City* Citylist::getFirstCity(Player* p) const
+{
+    for (const_iterator it = begin(); it != end(); it++)
+        if ((*it)->getOwner() == p)
+            return (*it);
+
+    return 0;
+}
+
+bool Citylist::save(XML_Helper* helper) const
+{
+    bool retval = true;
+
+    retval &= helper->openTag(Citylist::d_tag);
+
+    for (const_iterator it = begin(); it != end(); it++)
+        (*it)->save(helper);
+    
+    retval &= helper->closeTag();
+
+    return retval;
+}
+
+bool Citylist::load(std::string tag, XML_Helper* helper)
+{
+    if (tag == City::d_tag)
+      {
+       Cityset *cs = GameMap::getInstance()->getCityset();
+       City *c = new City(helper, cs->getCityTileWidth());
+       add(c);
+       return true;
+      }
+    return false;
+}
+
+void Citylist::changeOwnership(Player *old_owner, Player *new_owner)
+{
+  for (iterator it = begin(); it != end(); it++)
+    if ((*it)->getOwner() == old_owner)
+      {
+       (*it)->setOwner(new_owner);
+       if ((*it)->isCapital())
+         if ((*it)->getCapitalOwner() == old_owner)
+           (*it)->setCapitalOwner(new_owner);
+      }
+}
+
+void Citylist::stopVectoringTo(City *c)
+{
+  for (iterator it = begin(); it != end(); it++)
+    {
+      if ((*it)->isBurnt() == true)
+       continue;
+      if ((*it)->getVectoring() == Vector<int>(-1,-1))
+       continue;
+      if (c->contains((*it)->getVectoring()))
+       (*it)->setVectoring(Vector<int>(-1,-1));
+    }
+  return;
+}
+
+bool Citylist::isVectoringTarget(City *target) const
+{
+  for (const_iterator it = begin(); it != end(); it++)
+    {
+      if ((*it)->getOwner() != target->getOwner())
+       continue;
+      if (target->contains((*it)->getVectoring()))
+       return true;
+    }
+  return false;
+}
+
+std::list<City*> Citylist::getCitiesVectoringTo(Vector<int> target) const
+{
+  std::list<City*> cities;
+  for (const_iterator it = begin(); it != end(); it++)
+    {
+      if (target == (*it)->getVectoring())
+       cities.push_back((*it));
+    }
+  return cities;
+}
+
+std::list<City*> Citylist::getCitiesVectoringTo(City *target) const
+{
+  std::list<City*> cities;
+  for (const_iterator it = begin(); it != end(); it++)
+    {
+      if ((*it)->getOwner() != target->getOwner())
+       continue;
+      if (target->contains((*it)->getVectoring()))
+       cities.push_back((*it));
+    }
+  return cities;
+}
+
+City* Citylist::getNearestCityPast(const Vector<int>& pos, int dist) const
+{
+  std::list<bool (*)(void *)> filters;
+  filters.push_back(isBurnt);
+  return getNearestObjectAfter(pos, dist, &filters);
+}
+
+guint32 Citylist::countCitiesVectoringTo(const City *dest) const
+{
+  guint32 count = 0;
+  for (const_iterator it = begin(); it != end(); it++)
+    {
+      City *c = *it;
+      if (c->getOwner() != dest->getOwner())
+       continue;
+      if (c->getVectoring() == dest->getPos())
+       count++;
+    }
+
+  return count;
+}
+
+std::list<City*> Citylist::getNearestFriendlyCities(Player *player, Vector<int> pos) const
+{
+  std::list<City*> cities;
+  for (const_iterator it = begin(); it != end(); it++)
+    {
+      City *c = *it;
+      if (c->getOwner() != player)
+        continue;
+      if (c->isBurnt() == true)
+        continue;
+      cities.push_back(c);
+    }
+  if (cities.size() == 0)
+    return cities;
+  std::list<int> distances;
+
+  if (pos == Vector<int>(-1,-1))
+    pos = getFirstCity(player)->getPos();
+
+  for (std::list<City*>::iterator it = cities.begin(); it != cities.end(); it++)
+    distances.push_back(dist((*it)->getNearestPos(pos), pos));
+
+  bool sorted = false;
+
+  while (!sorted)
+    {
+      sorted = true;
+
+      // setup
+      std::list<int>::iterator dit = distances.begin();
+      std::list<int>::iterator dnextit = distances.begin();
+      dnextit++;
+
+      std::list<City*>::iterator it = cities.begin();
+      std::list<City*>::iterator nextit = it;
+      nextit++;
+
+      for (; nextit != cities.end(); it++, nextit++, dit++, dnextit++)
+        if ((*dit) > (*dnextit))
+          {
+            // exchange the items in both lists
+            sorted = false;
+
+            City* tmp = (*nextit);
+            cities.erase(nextit);
+            nextit = it;
+            it = cities.insert(nextit, tmp);
+
+            int val = (*dnextit);
+            distances.erase(dnextit);
+            dnextit = dit;
+            dit = distances.insert(dnextit, val);
+          }
+    }
+  return cities;
+}
+
+City *Citylist::getCapitalCity(Player *player) const
+{
+  for (const_iterator it = begin(); it != end(); it++)
+    {
+      City *c = *it;
+      if (c->getCapitalOwner() == player)
+        return c;
+    }
+  return NULL;
+}
+// End of file