1 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include "rectangle.h"
22 #include <sigc++/functors/mem_fun.h>
27 #include "GraphicsCache.h"
29 #include "gui/image-helpers.h"
30 #include "armysetlist.h"
31 #include "armyprodbase.h"
33 std::string Armyset::d_tag = "armyset";
34 std::string Armyset::file_extension = ARMYSET_EXT;
37 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
40 #define DEFAULT_ARMY_TILE_SIZE 40
41 Armyset::Armyset(guint32 id, std::string name)
42 : d_id(id), d_name(name), d_copyright(""), d_license(""), d_subdir(""),
43 d_tilesize(DEFAULT_ARMY_TILE_SIZE), d_ship(0), d_shipmask(0),
44 d_standard(0), d_standard_mask(0), d_bag(0)
47 d_stackship_name = "";
51 Armyset::Armyset(XML_Helper *helper, std::string directory)
52 : d_id(0), d_name(""), d_copyright(""), d_license(""), d_subdir(""),
53 d_tilesize(DEFAULT_ARMY_TILE_SIZE), d_ship(0), d_shipmask(0),
54 d_standard(0), d_standard_mask(0), d_bag(0)
57 d_stackship_name = "";
59 setDirectory(directory);
60 helper->getData(d_id, "id");
61 helper->getData(d_name, "name");
62 helper->getData(d_copyright, "copyright");
63 helper->getData(d_license, "license");
64 helper->getData(d_tilesize, "tilesize");
65 helper->getData(d_stackship_name, "stackship");
66 helper->getData(d_standard_name, "plantedstandard");
67 helper->getData(d_bag_name, "bag");
68 helper->registerTag(ArmyProto::d_tag,
69 sigc::mem_fun((*this), &Armyset::loadArmyProto));
74 uninstantiateImages();
75 for (iterator it = begin(); it != end(); it++)
79 bool Armyset::loadArmyProto(string tag, XML_Helper* helper)
81 if (tag == ArmyProto::d_tag)
84 ArmyProto* a = new ArmyProto(helper);
92 bool Armyset::save(XML_Helper* helper)
96 retval &= helper->openTag(d_tag);
98 retval &= helper->saveData("id", d_id);
99 retval &= helper->saveData("name", d_name);
100 retval &= helper->saveData("copyright", d_copyright);
101 retval &= helper->saveData("license", d_license);
102 retval &= helper->saveData("tilesize", d_tilesize);
103 retval &= helper->saveData("stackship", d_stackship_name);
104 retval &= helper->saveData("plantedstandard", d_standard_name);
105 retval &= helper->saveData("bag", d_bag_name);
107 for (const_iterator it = begin(); it != end(); it++)
110 retval &= helper->closeTag();
115 ArmyProto * Armyset::lookupSimilarArmy(ArmyProto *army) const
117 for (const_iterator it = begin(); it != end(); it++)
119 if ((*it)->getGender() == army->getGender() &&
120 (*it)->getStrength() == army->getStrength() &&
121 (*it)->getProduction() == army->getProduction() &&
122 (*it)->getArmyBonus() == army->getArmyBonus() &&
123 (*it)->getMoveBonus() == army->getMoveBonus() &&
124 (*it)->getMaxMoves() == army->getMaxMoves() &&
125 (*it)->getAwardable() == army->getAwardable() &&
126 (*it)->getDefendsRuins() == army->getDefendsRuins())
129 for (const_iterator it = begin(); it != end(); it++)
131 if ((*it)->getGender() == army->getGender() &&
132 (*it)->getStrength() == army->getStrength() &&
133 (*it)->getProduction() == army->getProduction() &&
134 (*it)->getArmyBonus() == army->getArmyBonus() &&
135 (*it)->getMoveBonus() == army->getMoveBonus() &&
136 (*it)->getMaxMoves() == army->getMaxMoves())
139 for (const_iterator it = begin(); it != end(); it++)
141 if ((*it)->getGender() == army->getGender() &&
142 (*it)->getStrength() == army->getStrength() &&
143 (*it)->getProduction() == army->getProduction() &&
144 (*it)->getMaxMoves() == army->getMaxMoves())
150 ArmyProto * Armyset::lookupArmyByGender(Hero::Gender gender) const
152 for (const_iterator it = begin(); it != end(); it++)
154 if ((*it)->getGender() == gender)
159 ArmyProto * Armyset::lookupArmyByStrengthAndTurns(guint32 str, guint32 turns) const
161 for (const_iterator it = begin(); it != end(); it++)
165 if ((*it)->getStrength() == str && (*it)->getProduction() == turns)
170 if ((*it)->getStrength() == str)
175 if ((*it)->getProduction() == turns)
182 ArmyProto * Armyset::lookupArmyByName(std::string name) const
184 for (const_iterator it = begin(); it != end(); it++)
186 if ((*it)->getName() == name)
192 ArmyProto * Armyset::lookupArmyByType(guint32 army_type_id) const
194 for (const_iterator it = begin(); it != end(); it++)
196 if ((*it)->getTypeId() == army_type_id)
202 bool Armyset::validateSize()
209 bool Armyset::validateHero()
213 for (iterator it = begin(); it != end(); it++)
215 if ((*it)->isHero() == true)
225 bool Armyset::validatePurchasables()
228 for (iterator it = begin(); it != end(); it++)
230 if ((*it)->getNewProductionCost() > 0 )
241 bool Armyset::validateRuinDefenders()
244 for (iterator it = begin(); it != end(); it++)
246 if ((*it)->getDefendsRuins() == true)
257 bool Armyset::validateAwardables()
260 for (iterator it = begin(); it != end(); it++)
262 if ((*it)->getAwardable() == true)
272 bool Armyset::validateShip()
274 if (getShipImageName() == "")
279 bool Armyset::validateBag()
281 if (getBagImageName() == "")
286 bool Armyset::validateStandard()
288 if (getStandardImageName() == "")
293 bool Armyset::validateArmyUnitImage(ArmyProto *army, Shield::Colour &c)
295 for (unsigned int i = Shield::WHITE; i <= Shield::NEUTRAL; i++)
296 if (army->getImageName(Shield::Colour(i)) == "")
298 c = Shield::Colour(i);
303 bool Armyset::validateArmyUnitImages()
306 for (iterator it = begin(); it != end(); it++)
308 if (validateArmyUnitImage(*it, c) == false)
314 bool Armyset::validateArmyUnitName(ArmyProto *army)
316 if (army->getName() == "")
320 bool Armyset::validateArmyUnitNames()
322 for (iterator it = begin(); it != end(); it++)
324 if (validateArmyUnitName(*it) == false)
329 bool Armyset::validate()
332 valid = validateSize();
335 valid = validateHero();
338 valid = validatePurchasables();
341 //do we have any units that defend ruins?
342 valid = validateRuinDefenders();
345 //do we have any units that can be awarded?
346 valid = validateAwardables();
349 //is the stackship set?
350 valid = validateShip();
353 //is the standard set?
354 valid = validateStandard();
358 valid = validateBag();
361 //is there an image set for each army unit?
362 valid = validateArmyUnitImages();
365 //is there a name set for each army unit?
366 valid = validateArmyUnitNames();
375 ArmysetLoader(std::string filename)
378 dir = File::get_dirname(filename);
379 if (File::nameEndsWith(filename, Armyset::file_extension) == false)
380 filename += Armyset::file_extension;
381 XML_Helper helper(filename, ios::in, false);
382 helper.registerTag(Armyset::d_tag, sigc::mem_fun((*this), &ArmysetLoader::load));
385 std::cerr << "Error, while loading an armyset. Armyset Name: ";
386 std::cerr <<File::get_basename(File::get_dirname(filename)) <<std::endl <<std::flush;
392 bool load(std::string tag, XML_Helper* helper)
394 if (tag == Armyset::d_tag)
396 armyset = new Armyset(helper, dir);
404 Armyset *Armyset::create(std::string filename)
406 ArmysetLoader d(filename);
409 void Armyset::getFilenames(std::list<std::string> &files)
411 for (iterator it = begin(); it != end(); it++)
413 for (unsigned int i = Shield::WHITE; i <= Shield::NEUTRAL; i++)
415 std::string file = (*it)->getImageName(Shield::Colour(i));
416 if (std::find(files.begin(), files.end(), file) == files.end())
417 files.push_back(file);
422 void Armyset::instantiateImages()
424 for (iterator it = begin(); it != end(); it++)
425 (*it)->instantiateImages(this);
426 if (getShipImageName().empty() == false)
427 loadShipPic(getFile(getShipImageName()));
428 if (getStandardImageName().empty() == false)
429 loadStandardPic(getFile(getStandardImageName()));
430 if (getBagImageName().empty() == false)
431 loadBagPic(getFile(getBagImageName()));
434 void Armyset::uninstantiateImages()
436 for (iterator it = begin(); it != end(); it++)
437 (*it)->uninstantiateImages();
440 void Armyset::loadShipPic(std::string image_filename)
442 if (image_filename.empty() == true)
444 std::vector<PixMask*> half;
445 half = disassemble_row(image_filename, 2);
446 int size = getTileSize();
447 PixMask::scale(half[0], size, size);
448 PixMask::scale(half[1], size, size);
449 setShipImage(half[0]);
450 setShipMask(half[1]);
453 void Armyset::loadBagPic(std::string image_filename)
455 if (image_filename.empty() == true)
457 setBagPic(PixMask::create(image_filename));
459 void Armyset::loadStandardPic(std::string image_filename)
461 if (image_filename.empty() == true)
463 std::vector<PixMask*> half = disassemble_row(image_filename, 2);
464 int size = getTileSize();
465 PixMask::scale(half[0], size, size);
466 PixMask::scale(half[1], size, size);
467 setStandardPic(half[0]);
468 setStandardMask(half[1]);
471 std::string Armyset::getConfigurationFile()
473 return getDirectory() + d_subdir + file_extension;
476 std::list<std::string> Armyset::scanUserCollection()
478 return File::scanFiles(File::getUserArmysetDir(), file_extension);
481 std::list<std::string> Armyset::scanSystemCollection()
483 std::list<std::string> retlist = File::scanFiles(File::getArmysetDir(),
487 std::cerr << "Couldn't find any armysets!" << std::endl;
488 std::cerr << "Please check the path settings in /etc/lordsawarrc or ~/.lordsawarrc" << std::endl;
489 std::cerr << "Exiting!" << std::endl;
496 void Armyset::switchArmysetForRuinKeeper(Army *army, const Armyset *armyset)
498 //do our best to change the armyset for the given ruin keeper.
500 //go find an equivalent type in the new armyset.
502 = Armysetlist::getInstance()->getArmyset(army->getOwner()->getArmyset());
503 ArmyProto *old_armyproto = old_armyset->lookupArmyByType(army->getTypeId());
504 const ArmyProto *new_armyproto = armyset->lookupArmyByType(army->getTypeId());
506 //try looking at the same id first
507 if (new_armyproto != NULL &&
508 old_armyproto->getName() == new_armyproto->getName() &&
509 old_armyproto->getDefendsRuins() == new_armyproto->getDefendsRuins())
511 army->morph(new_armyproto);
515 //try finding an army by the same name
516 new_armyproto = armyset->lookupArmyByName(old_armyproto->getName());
517 if (new_armyproto != NULL &&
518 old_armyproto->getDefendsRuins() == new_armyproto->getDefendsRuins())
520 army->morph(new_armyproto);
524 //failing that, any ruin keeper will do.
525 new_armyproto = armyset->getRandomRuinKeeper();
526 if (new_armyproto != NULL)
528 army->morph(new_armyproto);
534 void Armyset::switchArmyset(ArmyProdBase *army, const Armyset *armyset)
536 //do our best to change the armyset for the given armyprodbase.
538 //go find an equivalent type in the new armyset.
540 = Armysetlist::getInstance()->getArmyset(army->getArmyset());
541 ArmyProto *old_armyproto = old_armyset->lookupArmyByType(army->getTypeId());
542 ArmyProto *new_armyproto = armyset->lookupArmyByType(army->getTypeId());
544 //try looking at the same id first
545 if (new_armyproto != NULL &&
546 old_armyproto->getName() == new_armyproto->getName())
548 army->morph(new_armyproto);
552 //try finding an army by the same name
553 new_armyproto = armyset->lookupArmyByName(old_armyproto->getName());
554 if (new_armyproto != NULL)
556 army->morph(new_armyproto);
560 //failing that, any army with similar characteristics will do.
561 new_armyproto = armyset->lookupSimilarArmy(old_armyproto);
562 if (new_armyproto != NULL)
564 army->morph(new_armyproto);
568 //failing that, any army with the same strength and turns will do.
570 armyset->lookupArmyByStrengthAndTurns(old_armyproto->getStrength(),
571 old_armyproto->getProduction());
572 if (new_armyproto != NULL)
574 army->morph(new_armyproto);
578 //failing that, any army with the same strength will do.
580 armyset->lookupArmyByStrengthAndTurns(old_armyproto->getStrength(), 0);
581 if (new_armyproto != NULL)
583 army->morph(new_armyproto);
587 //failing that, any army with the same turns will do.
589 armyset->lookupArmyByStrengthAndTurns(0, old_armyproto->getProduction());
590 if (new_armyproto != NULL)
592 army->morph(new_armyproto);
596 //failing that, any army will do.
597 new_armyproto = armyset->lookupArmyByGender(old_armyproto->getGender());
598 if (new_armyproto != NULL)
600 army->morph(new_armyproto);
606 void Armyset::switchArmyset(Army *army, const Armyset *armyset)
608 //do our best to change the armyset for the given army.
610 //go find an equivalent type in the new armyset.
612 = Armysetlist::getInstance()->getArmyset(army->getOwner()->getArmyset());
613 ArmyProto *old_armyproto = old_armyset->lookupArmyByType(army->getTypeId());
614 ArmyProto *new_armyproto = armyset->lookupArmyByType(army->getTypeId());
616 //try looking at the same id first
617 if (new_armyproto != NULL &&
618 old_armyproto->getName() == new_armyproto->getName())
620 army->morph(new_armyproto);
624 //try finding an army by the same name
625 new_armyproto = armyset->lookupArmyByName(old_armyproto->getName());
626 if (new_armyproto != NULL)
628 army->morph(new_armyproto);
632 //failing that, an army with the same gender (heroes).
633 if (army->isHero() == true)
635 new_armyproto = armyset->lookupArmyByGender(old_armyproto->getGender());
636 if (new_armyproto != NULL)
638 army->morph(new_armyproto);
643 //failing that, any army with similar characteristics will do.
644 new_armyproto = armyset->lookupSimilarArmy(old_armyproto);
645 if (new_armyproto != NULL)
647 army->morph(new_armyproto);
651 //failing that, any army with the same strength and turns will do.
653 armyset->lookupArmyByStrengthAndTurns(old_armyproto->getStrength(),
654 old_armyproto->getProduction());
655 if (new_armyproto != NULL)
657 army->morph(new_armyproto);
661 //failing that, any army with the same strength will do.
663 armyset->lookupArmyByStrengthAndTurns(old_armyproto->getStrength(), 0);
664 if (new_armyproto != NULL)
666 army->morph(new_armyproto);
670 //failing that, any army with the same turns will do.
672 armyset->lookupArmyByStrengthAndTurns(0, old_armyproto->getProduction());
673 if (new_armyproto != NULL)
675 army->morph(new_armyproto);
679 //failing that, any army will do.
680 new_armyproto = armyset->lookupArmyByGender(old_armyproto->getGender());
681 if (new_armyproto != NULL)
683 army->morph(new_armyproto);
689 const ArmyProto * Armyset::getRandomRuinKeeper() const
691 // list all the army types that can be a sentinel.
692 std::vector<const ArmyProto*> occupants;
693 for (const_iterator i = begin(); i != end(); i++)
695 const ArmyProto *a = *i;
696 if (a->getDefendsRuins())
697 occupants.push_back(a);
700 if (!occupants.empty())
701 return occupants[rand() % occupants.size()];
706 const ArmyProto *Armyset::getRandomAwardableAlly() const
708 // list all the army types that can be given out as a reward.
709 std::vector<const ArmyProto*> allies;
710 for (const_iterator i = begin(); i != end(); i++)
712 const ArmyProto *a = *i;
713 if (a->getAwardable() == true)
718 return allies[rand() % allies.size()];