1 //  Copyright (C) 2007, 2008, 2009, 2010, 2011, 2014, 2015, 2020 Ben Asselstine
2 //
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.
7 //
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.
12 //
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
16 //  02110-1301, USA.
17 
18 #pragma once
19 #ifndef ARMYSET_H
20 #define ARMYSET_H
21 
22 #include <gtkmm.h>
23 #include <map>
24 #include <vector>
25 #include <sigc++/trackable.h>
26 
27 #include "armyproto.h"
28 #include "set.h"
29 #include "hero.h"
30 
31 //! A collection of Army prototype objects.
32 /**
33  * An Armyset is a complete set of Army prototype objects.  An Army prototype
34  * is a kind of Army, as opposed to an Army unit instance (e.g. on the game
35  * map).  See the Army class for more information about what an Army prototype
36  * is.  The Armyset describes the size of the graphic tiles that each Army
37  * graphic occupies on the screen (Army::d_tilesize).
38  * There special images are kept with the Armyset:  the ship picture, the
39  * planted standard picture, and the bag of items picture.
40  *
41  * The ship picture is what the Stack looks like when it is in a boat.
42  * The planted standard is what the player's standard looks like when it has
43  * been planted in the ground.  The bag of items picture is what it looks like
44  * when a hero has dropped an item on the ground.
45  *
46  * Armysets are most often referred to by their Id (Armyset::d_id), but may
47  * sometimes be referred to by their name (Armyset::d_name) or basename
48  * name (Armyset::d_basename).
49  *
50  * Armyset objects are loaded from an armyset configuration file.
51  *
52  * Armyset objects are created by the armyset editor.
53  *
54  * Every Player has an Armyset that dictates the characteristics of the
55  * player's forces, but in practise there is only one Armyset per scenario.
56  *
57  * The armyset configuration file is a tar file that contains an XML file,
58  * and a set of png files.  Filenames have the following form:
59  * army/${Armyset::d_basename}.lwa.
60  */
61 class Armyset: public std::list<ArmyProto *>, public sigc::trackable, public Set
62 {
63     public:
64 
65 	//! The xml tag of this object in an armyset configuration file.
66 	static Glib::ustring d_tag;
67 	static Glib::ustring file_extension;
68 
69 	//! Default constructor.
70 	/**
71 	 * Make a new Armyset.
72 	 *
73 	 * @param id    The unique Id of this Armyset among all other Armyset
74 	 *              objects.  Must be more than 0.
75 	 * @param name  The name of the Armyset.  Analagous to Armyset::d_name.
76 	 */
77 	Armyset(guint32 id, Glib::ustring name);
78 	//! Loading constructor.
79 	/**
80 	 * Load armyset XML entities from armyset configuration files.
81 	 */
82         Armyset(XML_Helper* helper, Glib::ustring directory);
83 
84         //! Copy constructor.
85         Armyset(const Armyset& armyset);
86 
87 	static Armyset *create(Glib::ustring filename, bool &unsupported);
88 
89         static Armyset *copy (const Armyset *orig);
90 
91 	//! Destructor.
92         ~Armyset();
93 
94 	/**
95 	 * @param helper  An opened armyset configuration file.
96 	 */
97 	//! Save the Armyset to an Armyset configuration file.
98 	bool save(XML_Helper* helper) const;
99 
100         bool save(Glib::ustring filename, Glib::ustring ext) const;
101 
102 	//! Get the image of the stack in a ship (minus the mask).
getShipPic()103 	PixMask* getShipPic() const {return d_ship;}
104 
105 	//! Set the image of the stack in a ship
setShipImage(PixMask * ship)106 	void setShipImage(PixMask* ship) {d_ship = ship;};
107 
108 	//! Get the mask portion of the image of the stack in a ship.
getShipMask()109 	PixMask* getShipMask() const {return d_shipmask;}
110 
111 	//! Set the mask portion of the image of the stack in a ship.
setShipMask(PixMask * shipmask)112 	void setShipMask(PixMask* shipmask) {d_shipmask = shipmask;};
113 
114         //! Clear the ship name, pic, and mask
115         void clearShipImage (bool clear_name = true);
116 
117         //! Instantiate the ship image by loading it from the lwa file.
118         bool instantiateShipImage ();
119 
120 	//! Get the image of the bag.
getBagPic()121 	PixMask* getBagPic() const {return d_bag;}
122 
123 	//! Set the image of the bag.
setBagPic(PixMask * s)124 	void setBagPic(PixMask* s) {d_bag = s;};
125 
126         //! Clear the bag name and pic
127         void clearBagImage (bool clear_name = true);
128 
129         //! Instantiate the bag image by loading it from the lwa file.
130         bool instantiateBagImage ();
131 
132 	//! Get the image of the planted standard (minus the mask).
getStandardPic()133 	PixMask* getStandardPic() const {return d_standard;}
134 
135 	//! Set the image of the planted standard (minus the mask).
setStandardPic(PixMask * s)136 	void setStandardPic(PixMask* s) {d_standard = s;};
137 
138 	//! Get the mask portion of the image of the planted standard.
getStandardMask()139 	PixMask* getStandardMask() const {return d_standard_mask;}
140 
141 	//! Set the mask portion of the image of the planted standard.
setStandardMask(PixMask * s)142 	void setStandardMask(PixMask* s) {d_standard_mask = s;};
143 
144         //! Clear the standard (hero's flag) name, pic and mask
145         void clearStandardImage (bool clear_name = true);
146 
147         //! Instantiate the standard image by loading it from the lwa file.
148         bool instantiateStandardImage ();
149 
150 	//! Set the name of the file holding the image of the stack in a boat.
setShipImageName(Glib::ustring n)151 	void setShipImageName(Glib::ustring n) {d_stackship_name = n;};
152 
153 	//! Get the name of the file holding the image of the stack in a boat.
getShipImageName()154 	Glib::ustring getShipImageName() {return d_stackship_name;};
155 
156 	//! Set the name of the file holding the image of the hero's flag.
setStandardImageName(Glib::ustring n)157 	void setStandardImageName(Glib::ustring n) {d_standard_name = n;};
158 
159 	//! Get the name of the file holding the image of the hero's flag.
getStandardImageName()160 	Glib::ustring getStandardImageName() {return d_standard_name;};
161 
162 	//! Set the name of the file holding the image of the bag.
setBagImageName(Glib::ustring n)163 	void setBagImageName(Glib::ustring n) {d_bag_name = n;};
164 
165 	//! Get the name of the file holding the image of the bag.
getBagImageName()166 	Glib::ustring getBagImageName() {return d_bag_name;};
167 
168         //! Find the type id with the highest value and return it.
169         guint32 getMaxId() const;
170 
171 	//! Find an army with a type in this armyset.
172 	/**
173 	 * Scan the Army prototype objects in this Armyset and return it.
174 	 *
175 	 * @note This is only used for the editor.  Most callers should use
176 	 * Armysetlist::getArmy instead.
177 	 *
178 	 * @param army_type  The army type id of the Army prototype object
179 	 *                   to search for in this Armyset.
180 	 *
181 	 * @return The Army with the given army type id, or NULL if none
182 	 *         could be found.
183 	 */
184 	ArmyProto * lookupArmyByType(guint32 army_type) const;
185 
186 	ArmyProto * lookupArmyByName(Glib::ustring name) const;
187 
188 	ArmyProto * lookupArmyByStrengthAndTurns(guint32 str, guint32 turns) const;
189 
190 	ArmyProto * lookupArmyByGender(Hero::Gender gender) const;
191 
192 	ArmyProto * lookupSimilarArmy(ArmyProto *army) const;
193 
194         ArmyProto * lookupWeakestQuickestArmy() const;
195 
196 	//! can this armyset be used within the game?
197 	bool validate();
198 	bool validateHero();
199 	bool validatePurchasables();
200 	bool validateRuinDefenders();
201 	bool validateAwardables();
202 	bool validateShip();
203 	bool validateStandard();
204 	bool validateBag();
205 	bool validateArmyUnitImages();
206 	bool validateArmyUnitImage(ArmyProto *a, Shield::Colour &c);
207 	bool validateArmyUnitNames();
208 	bool validateArmyUnitName(ArmyProto *a);
209 	bool validateArmyTypeIds();
210 
211         //! Load the images associated with this armyset.
212         /**
213          * Go get the image files from the armyset file and create the
214          * various pixmask objects.
215          *
216          * @param scale   The images are clamped to the tile size or not.
217          * @param broken  True when things went wrong reading the armyset file.
218          */
219 	void instantiateImages(bool scale, bool &broken);
220 	void uninstantiateImages();
221         void uninstantiateSameNamedImages (Glib::ustring name);
222 
223 	void loadStandardPic(Glib::ustring image_filename, bool scale, bool &broken);
224 	void loadShipPic(Glib::ustring image_filename, bool scale, bool &broken);
225 	void loadBagPic(Glib::ustring image_filename, bool &broken);
226 
227 	static void switchArmyset(Army *army, const Armyset *armyset);
228 	static void switchArmyset(ArmyProdBase *army, const Armyset *armyset);
229 	static void switchArmysetForRuinKeeper(Army *army, const Armyset *armyset);
230 	const ArmyProto * getRandomRuinKeeper() const;
231 	const ArmyProto *getRandomAwardableAlly() const;
232 
233         //! Load the armyset again.
234         void reload(bool &broken);
235         bool calculate_preferred_tile_size(guint32 &ts) const;
236 
237         //! callback to upgrade old files.
238         static bool upgrade(Glib::ustring filename, Glib::ustring old_version, Glib::ustring new_version);
239         static void support_backward_compatibility();
240 
241         static guint32 get_default_tile_size ();
242     private:
243 
244         //! Callback function for the army tag (see XML_Helper)
245         bool loadArmyProto(Glib::ustring tag, XML_Helper* helper);
246 
247 	//! The unshaded picture of the stack when it's in a boat.
248 	PixMask* d_ship;
249 
250 	//! The mask of what to shade with the player's colour on the boat.
251 	PixMask* d_shipmask;
252 
253 	//! The unshaded picture of the planted standard.
254 	PixMask* d_standard;
255 
256 	//! The mask of what to shade with the player's colour on the standard.
257 	PixMask* d_standard_mask;
258 
259 	//! The picture of an item when it's lying on the ground.
260 	PixMask *d_bag;
261 
262 	//! The name of the file that holds the picture of the hero's flag.
263 	Glib::ustring d_standard_name;
264 
265 	//! The name of the file that holds the picture of stack on water.
266 	Glib::ustring d_stackship_name;
267 
268 	//! The name of the file that holds the picture of the sack of items.
269 	Glib::ustring d_bag_name;
270 };
271 
272 bool weakest_quickest (const ArmyProto* first, const ArmyProto* second);
273 #endif // ARMYSET_H
274 
275