1 // Copyright (C) 2000, 2001, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2002 Mark L. Amidon
4 // Copyright (C) 2005 Andrea Paternesi
5 // Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
6 // Copyright (C) 2008 Ole Laursen
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.
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.
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
30 #include "armyprodbase.h"
32 #include "stacklist.h"
34 #include "playerlist.h"
35 #include "armysetlist.h"
38 #include "vectoredunitlist.h"
39 #include "vectoredunit.h"
42 std::string City::d_tag = "city";
46 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
49 City::City(Vector<int> pos, guint32 width, string name, guint32 gold,
51 :Ownable((Player *)0), Location(pos, width), Renamable(name),
52 ProdSlotlist(numslots), d_gold(gold), d_defense_level(1), d_burnt(false),
53 d_vectoring(false), d_vector(Vector<int>(-1,-1)),
54 d_capital(false), d_capital_owner(0)
57 // set the tiles to city type
58 for (unsigned int i = 0; i < getSize(); i++)
59 for (unsigned int j = 0; j < getSize(); j++)
61 Vector<int> pos = getPos() + Vector<int>(i, j);
62 GameMap::getInstance()->getTile(pos)->setBuilding(Maptile::CITY);
66 City::City(XML_Helper* helper, guint32 width)
67 :Ownable(helper), Location(helper, width), Renamable(helper),
72 helper->getData(d_defense_level, "defense");
74 helper->getData(d_gold, "gold");
75 helper->getData(d_burnt, "burnt");
76 helper->getData(d_capital, "capital");
80 helper->getData(ui, "capital_owner");
81 d_capital_owner = Playerlist::getInstance()->getPlayer(ui);
88 helper->getData(s, "vectoring");
93 if (d_vector.x!=-1 && d_vector.y!=-1)
98 //mark the positions on the map as being occupied by a city
99 for (unsigned int i = 0; i < d_size; i++)
100 for (unsigned int j = 0; j < d_size; j++)
101 GameMap::getInstance()->getTile(getPos().x+i, getPos().y+j)
102 ->setBuilding(Maptile::CITY);
105 City::City(const City& c)
106 :Ownable(c), Location(c), Renamable(c), ProdSlotlist(c),
107 d_gold(c.d_gold), d_defense_level(c.d_defense_level), d_burnt(c.d_burnt),
108 d_vectoring(c.d_vectoring),d_vector(c.d_vector), d_capital(c.d_capital),
109 d_capital_owner(c.d_capital_owner)
113 City::City(const City& c, Vector<int> pos)
114 :Ownable(c), Location(c, pos), Renamable(c), ProdSlotlist(c),
115 d_gold(c.d_gold), d_defense_level(c.d_defense_level), d_burnt(c.d_burnt),
116 d_vectoring(c.d_vectoring),d_vector(c.d_vector), d_capital(c.d_capital),
117 d_capital_owner(c.d_capital_owner)
125 bool City::save(XML_Helper* helper) const
131 svect << d_vector.x << " " << d_vector.y;
133 retval &= helper->openTag(City::d_tag);
134 retval &= helper->saveData("id", d_id);
135 retval &= helper->saveData("x", getPos().x);
136 retval &= helper->saveData("y", getPos().y);
137 retval &= helper->saveData("name", getName(false));
138 retval &= helper->saveData("owner", d_owner->getId());
139 retval &= helper->saveData("defense", d_defense_level);
140 retval &= helper->saveData("gold", d_gold);
141 retval &= helper->saveData("burnt", d_burnt);
142 retval &= helper->saveData("capital", d_capital);
144 retval &= helper->saveData("capital_owner", d_capital_owner->getId());
145 retval &= helper->saveData("vectoring", svect.str());
147 retval &= ProdSlotlist::save(helper);
148 retval &= helper->closeTag();
152 void City::conquer(Player* newowner)
154 Citylist::getInstance()->stopVectoringTo(this);
158 // remove vectoring info
159 setVectoring(Vector<int>(-1,-1));
163 VectoredUnitlist *vul = VectoredUnitlist::getInstance();
164 vul->removeVectoredUnitsGoingTo(this);
165 vul->removeVectoredUnitsComingFrom(this);
168 void City::produceStrongestProductionBase()
170 debug("produceStrongestProductionBase()");
172 if (getNoOfProductionBases() == 0)
175 if (!isFull(d_owner))
177 unsigned int max_strength = 0;
179 for (unsigned int i = 0; i < getMaxNoOfProductionBases(); i++)
181 if ((*this)[i]->getArmyProdBase() == NULL)
183 if (getProductionBase(i)->getStrength() > max_strength)
186 max_strength = getProductionBase(i)->getStrength();
189 if (strong_idx == -1)
192 int savep = d_active_production_slot;
193 setActiveProductionSlot(strong_idx);
196 setActiveProductionSlot(savep);
201 void City::produceScout()
203 const Armysetlist* al = Armysetlist::getInstance();
204 guint32 set = d_owner->getArmyset();
205 ArmyProto *scout = al->getScout(set);
206 Army *a = new Army(*scout, d_owner);
207 GameMap::getInstance()->addArmy(this, a);
211 void City::produceWeakestProductionBase()
213 debug("produceWeakestProductionBase()");
215 if (getNoOfProductionBases() == 0)
218 if (!isFull(d_owner))
220 unsigned int min_strength = 100;
222 for (unsigned int i = 0; i < getMaxNoOfProductionBases(); i++)
224 if ((*this)[i]->getArmyProdBase() == NULL)
226 if (getProductionBase(i)->getStrength() < min_strength)
229 min_strength = getProductionBase(i)->getStrength();
235 int savep = d_active_production_slot;
236 setActiveProductionSlot(weak_idx);
239 setActiveProductionSlot(savep);
244 const Army *City::armyArrives(Vector<int> &pos)
246 // vector the army to the new spot
249 VectoredUnitlist *vul = VectoredUnitlist::getInstance();
250 VectoredUnit *v = new VectoredUnit
252 (*this)[d_active_production_slot]->getArmyProdBase(),
253 MAX_TURNS_FOR_VECTORING, d_owner);
255 d_owner->cityChangeProduction(this, d_active_production_slot);
256 //we don't return an army when we've vectored it.
257 //it doesn't really exist until it lands at the destination.
260 else //or make it here
262 return produceArmy(pos);
267 void City::nextTurn()
272 // check if an army should be produced
273 if (d_active_production_slot >= 0 && --d_duration == 0)
275 if (d_owner->getGold() <= 0)
277 //dont make or vector the unit
278 //and also stop production
279 d_owner->cityChangeProduction(this, -1);
280 d_owner->vectorFromCity(this, Vector<int>(-1,-1));
284 d_owner->cityProducesArmy(this);
289 void City::setVectoring(Vector<int> p)
294 if (p.x == -1 || p.y == -1)
302 Army *City::produceArmy(Vector<int> &pos)
304 // add produced army to stack
305 if (d_active_production_slot == -1)
308 debug("produce_army()\n");
310 // do not produce an army if the player has no gold.
311 // unless it's the neutrals
312 if (d_owner != Playerlist::getInstance()->getNeutral() &&
313 d_owner->getGold() < 0)
316 Army *a = new Army(*(getProductionBase(d_active_production_slot)), d_owner);
317 Stack *s = GameMap::getInstance()->addArmy(this, a);
320 if (d_owner == Playerlist::getInstance()->getNeutral())
322 //we're an active neutral city
323 //check to see if we've made 5 or not.
324 //stop producing if we've made 5 armies in our neutral city
325 if (countDefenders() >= MAX_ARMIES_PRODUCED_IN_NEUTRAL_CITY)
326 setActiveProductionSlot(-1);
328 setActiveProductionSlot(d_active_production_slot);
330 else // start producing next army of same type
331 setActiveProductionSlot(d_active_production_slot);
335 bool City::canAcceptMoreVectoring() const
337 return canAcceptMoreVectoring(0);
340 bool City::canAcceptMoreVectoring(guint32 number_of_cities) const
342 //here we presume that it's one unit per city
343 guint32 num = Citylist::getInstance()->countCitiesVectoringTo(this);
344 if (num + number_of_cities >= MAX_CITIES_VECTORED_TO_ONE_CITY)
349 bool City::changeVectorDestination(Vector<int> dest)
351 VectoredUnitlist *vul = VectoredUnitlist::getInstance();
353 vul->changeDestination(this, dest);
357 std::vector<Stack *> City::getDefenders() const
359 return getOwner()->getStacklist()->getDefendersInCity(this);
362 guint32 City::countDefenders() const
364 std::vector<Stack*> defenders;
365 defenders = getDefenders();
368 std::vector<Stack*>::iterator it = defenders.begin();
369 for (;it != defenders.end(); it++)
370 armies += (*it)->size();
375 void City::randomlyImproveOrDegradeArmy(ArmyProdBase *army)
377 if (rand() % 30 == 0) //random chance of improving strength
378 army->setStrength(army->getStrength() + 1);
379 if (rand() % 25 == 0) //random chance of improving turns
381 if (army->getProduction() > 1)
382 army->setProduction(army->getProduction() - 1);
384 if (rand() % 50 == 0) //random chance of degrading strength
386 if (army->getStrength() > 1)
387 army->setStrength(army->getStrength() - 1);
389 if (rand() % 45 == 0) //random chance of improving turns
391 if (army->getProduction() < 5)
392 army->setProduction(army->getProduction() + 1);
396 bool armyCompareStrength (const ArmyProdBase *lhs, const ArmyProdBase *rhs)
398 guint32 lhs_strength = lhs->getStrength();
399 guint32 rhs_strength = rhs->getStrength();
400 return lhs_strength < rhs_strength;
403 void City::sortProduction()
405 //sort them by strength
406 if (getNoOfProductionBases() > 1)
408 std::list<ArmyProdBase*> productibles;
410 for (j = 0; j < getMaxNoOfProductionBases(); j++)
412 if ((*this)[j]->getArmyProdBase())
413 productibles.push_back((*this)[j]->getArmyProdBase());
415 productibles.sort(armyCompareStrength);
417 for (std::list<ArmyProdBase*>::iterator it = productibles.begin();
418 it != productibles.end(); it++, j++)
419 (*this)[j]->setArmyProdBase(*it);
424 void City::setRandomArmytypes(bool produce_allies, int likely)
426 //remove armies any that happen to be being produced
427 for (unsigned int i = 0; i < getMaxNoOfProductionBases(); i++)
428 removeProductionBase(i);
430 const Armysetlist* al = Armysetlist::getInstance();
431 guint32 set = d_owner->getArmyset();
434 int num = rand() % 10;
437 else if (num < 9 && likely == 0)
440 army_type = 1 + likely + (rand () % 11);
441 ArmyProto *template_army = al->getArmy(set, army_type);
442 if (!template_army ||
443 (template_army->getAwardable() == true && produce_allies == false) ||
444 template_army->isHero())
449 ArmyProdBase *army = new ArmyProdBase (*template_army);
450 randomlyImproveOrDegradeArmy(army);
451 addProductionBase(0, army);
453 if (((rand() % 10) < 3 && !isCapital() && likely < 1) ||
454 template_army->getAwardable())
460 army_type += 1 + (rand() % (2 + (produce_allies ? 2 : 0)));
461 template_army = al->getArmy(set, army_type);
462 if (!template_army ||
463 (template_army->getAwardable() == true && produce_allies == false) ||
464 template_army->isHero())
469 army = new ArmyProdBase (*template_army);
470 randomlyImproveOrDegradeArmy(army);
471 addProductionBase(1, army);
473 if (((rand() % 10) < 4 && !isCapital() && likely < 2) ||
474 template_army->getAwardable())
481 army_type += 1 + (rand() % (7 + (produce_allies ? 2 : 0)));
483 army_type += 1 + (rand() % (2 + (produce_allies ? 2 : 0)));
484 template_army = al->getArmy(set, army_type);
485 if (!template_army ||
486 (template_army->getAwardable() == true && produce_allies == false) ||
487 template_army->isHero())
492 army = new ArmyProdBase (*template_army);
493 randomlyImproveOrDegradeArmy(army);
494 addProductionBase(2, army);
496 if (((rand() % 10) < 6 && !isCapital() && likely < 3) ||
497 template_army->getAwardable())
503 army_type += 1 + (rand() % (3 + (produce_allies ? 2 : 0)));
504 template_army = al->getArmy(set, army_type);
505 if (!template_army ||
506 (template_army->getAwardable() == true && produce_allies == false) ||
507 template_army->isHero())
512 army = new ArmyProdBase (*template_army);
513 randomlyImproveOrDegradeArmy(army);
514 addProductionBase(3, army);
518 guint32 City::calculateDefenseLevel() const
520 int num_production_bases = getNoOfProductionBases();
523 else if (num_production_bases <= 2 &&
524 getOwner() == Playerlist::getInstance()->getNeutral())
526 else if (num_production_bases <= 2)
528 else if (num_production_bases > 2 &&
529 getOwner() == Playerlist::getInstance()->getNeutral())
531 else if (num_production_bases > 2)