1 /*
2  * Copyright (C) 2002-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_TRAININGSITE_H
21 #define WL_LOGIC_MAP_OBJECTS_TRIBES_TRAININGSITE_H
22 
23 #include "base/macros.h"
24 #include "logic/map_objects/tribes/productionsite.h"
25 #include "logic/map_objects/tribes/soldiercontrol.h"
26 #include "logic/map_objects/tribes/training_attribute.h"
27 
28 struct TrainingSiteWindow;
29 
30 namespace Widelands {
31 
32 class World;
33 
34 class TrainingSiteDescr : public ProductionSiteDescr {
35 public:
36 	TrainingSiteDescr(const std::string& init_descname,
37 	                  const std::string& msgctxt,
38 	                  const LuaTable& table,
39 	                  const Tribes& tribes,
40 	                  const World& world);
~TrainingSiteDescr()41 	~TrainingSiteDescr() override {
42 	}
43 
44 	Building& create_object() const override;
45 
get_max_number_of_soldiers()46 	Quantity get_max_number_of_soldiers() const {
47 		return num_soldiers_;
48 	}
get_train_health()49 	bool get_train_health() const {
50 		return train_health_;
51 	}
get_train_attack()52 	bool get_train_attack() const {
53 		return train_attack_;
54 	}
get_train_defense()55 	bool get_train_defense() const {
56 		return train_defense_;
57 	}
get_train_evade()58 	bool get_train_evade() const {
59 		return train_evade_;
60 	}
61 
62 	int32_t get_min_level(TrainingAttribute) const;
63 	int32_t get_max_level(TrainingAttribute) const;
64 	int32_t get_max_stall() const;
65 
get_food_health()66 	const std::vector<std::vector<std::string>>& get_food_health() const {
67 		return food_health_;
68 	}
get_food_attack()69 	const std::vector<std::vector<std::string>>& get_food_attack() const {
70 		return food_attack_;
71 	}
get_food_defense()72 	const std::vector<std::vector<std::string>>& get_food_defense() const {
73 		return food_defense_;
74 	}
get_food_evade()75 	const std::vector<std::vector<std::string>>& get_food_evade() const {
76 		return food_evade_;
77 	}
get_weapons_health()78 	const std::vector<std::string>& get_weapons_health() const {
79 		return weapons_health_;
80 	}
get_weapons_attack()81 	const std::vector<std::string>& get_weapons_attack() const {
82 		return weapons_attack_;
83 	}
get_weapons_defense()84 	const std::vector<std::string>& get_weapons_defense() const {
85 		return weapons_defense_;
86 	}
get_weapons_evade()87 	const std::vector<std::string>& get_weapons_evade() const {
88 		return weapons_evade_;
89 	}
90 
91 private:
92 	// Read the table to add needed food and weapons for training a property.
93 	// Properties are health, attack, defense, and evade.
94 	void add_training_inputs(const LuaTable& table,
95 	                         std::vector<std::vector<std::string>>* food,
96 	                         std::vector<std::string>* weapons);
97 
98 	//  TODO(unknown): These variables should be per soldier type. They should be in a
99 	//  struct and there should be a vector, indexed by Soldier_Index,
100 	//  with that struct structs as element type.
101 	/** Maximum number of soldiers for a training site*/
102 	Quantity num_soldiers_;
103 	/** Number of rounds w/o successful training, after which a soldier is kicked out.**/
104 	uint32_t max_stall_;
105 	/** Whether this site can train health*/
106 	bool train_health_;
107 	/** Whether this site can train attack*/
108 	bool train_attack_;
109 	/** Whether this site can train defense*/
110 	bool train_defense_;
111 	/** Whether this site can train evasion*/
112 	bool train_evade_;
113 
114 	/** Minimum health to which a soldier can drop at this site*/
115 	int32_t min_health_;
116 	/** Minimum attacks to which a soldier can drop at this site*/
117 	int32_t min_attack_;
118 	/** Minimum defense to which a soldier can drop at this site*/
119 	int32_t min_defense_;
120 	/** Minimum evasion to which a soldier can drop at this site*/
121 	int32_t min_evade_;
122 
123 	/** Maximum health a soldier can acquire at this site*/
124 	int32_t max_health_;
125 	/** Maximum attack a soldier can acquire at this site*/
126 	int32_t max_attack_;
127 	/** Maximum defense a soldier can acquire at this site*/
128 	int32_t max_defense_;
129 	/** Maximum evasion a soldier can acquire at this site*/
130 	int32_t max_evade_;
131 
132 	// For building help
133 	std::vector<std::vector<std::string>> food_health_;
134 	std::vector<std::vector<std::string>> food_attack_;
135 	std::vector<std::vector<std::string>> food_defense_;
136 	std::vector<std::vector<std::string>> food_evade_;
137 	std::vector<std::string> weapons_health_;
138 	std::vector<std::string> weapons_attack_;
139 	std::vector<std::string> weapons_defense_;
140 	std::vector<std::string> weapons_evade_;
141 
142 	DISALLOW_COPY_AND_ASSIGN(TrainingSiteDescr);
143 };
144 
145 /**
146  * A building to change soldiers' abilities.
147  * Soldiers can gain health, or experience in attack, defense and evasion.
148  *
149  * \note  A training site does not change influence areas. If you lose the
150  *        surrounding strongholds, the training site will burn even if it
151  *        contains soldiers!
152  */
153 class TrainingSite : public ProductionSite {
154 	friend class MapBuildingdataPacket;
155 	MO_DESCR(TrainingSiteDescr)
156 	friend struct ::TrainingSiteWindow;
157 
158 	struct Upgrade {
159 		TrainingAttribute attribute;  // attribute for this upgrade
160 		std::string prefix;           // prefix for programs
161 		int32_t min, max;             // minimum and maximum program number (inclusive)
162 		uint32_t prio;                // relative priority
163 		uint32_t credit;              // whenever an upgrade gets credit >= 10, it can be run
164 		int32_t lastattempt;          // level of the last attempt in this upgrade category
165 
166 		// whether the last attempt in this upgrade category was successful
167 		bool lastsuccess;
168 		uint32_t failures;
169 	};
170 
171 public:
172 	explicit TrainingSite(const TrainingSiteDescr&);
173 
174 	bool init(EditorGameBase&) override;
175 	void cleanup(EditorGameBase&) override;
176 	void act(Game&, uint32_t data) override;
177 
178 	void add_worker(Worker&) override;
179 	void remove_worker(Worker&) override;
180 
get_build_heroes()181 	bool get_build_heroes() {
182 		return build_heroes_;
183 	}
set_build_heroes(bool b_heroes)184 	void set_build_heroes(bool b_heroes) {
185 		build_heroes_ = b_heroes;
186 	}
switch_heroes()187 	void switch_heroes() {
188 		build_heroes_ = !build_heroes_;
189 		molog("BUILD_HEROES: %s", build_heroes_ ? "TRUE" : "FALSE");
190 	}
191 
192 	void set_economy(Economy* e, WareWorker type) override;
193 
194 	int32_t get_pri(enum TrainingAttribute atr);
195 	void set_pri(enum TrainingAttribute atr, int32_t prio);
196 
197 	// These are for premature soldier kick-out
198 	void training_attempted(TrainingAttribute type, uint32_t level);
199 	void training_successful(TrainingAttribute type, uint32_t level);
200 	void training_done();
201 
202 	const BuildingSettings* create_building_settings() const override;
203 
204 protected:
205 	void program_end(Game&, ProgramResult) override;
206 
207 private:
208 	class SoldierControl : public Widelands::SoldierControl {
209 	public:
SoldierControl(TrainingSite * training_site)210 		explicit SoldierControl(TrainingSite* training_site) : training_site_(training_site) {
211 		}
212 
213 		std::vector<Soldier*> present_soldiers() const override;
214 		std::vector<Soldier*> stationed_soldiers() const override;
215 		Quantity min_soldier_capacity() const override;
216 		Quantity max_soldier_capacity() const override;
217 		Quantity soldier_capacity() const override;
218 		void set_soldier_capacity(Quantity capacity) override;
219 		void drop_soldier(Soldier&) override;
220 		int incorporate_soldier(EditorGameBase& game, Soldier& s) override;
221 
222 	private:
223 		TrainingSite* const training_site_;
224 	};
225 	void update_soldier_request(bool);
226 	static void
227 	request_soldier_callback(Game&, Request&, DescriptionIndex, Worker*, PlayerImmovable&);
228 
229 	void find_and_start_next_program(Game&) override;
230 	void start_upgrade(Game&, Upgrade&);
231 	void add_upgrade(TrainingAttribute, const std::string& prefix);
232 	void calc_upgrades();
233 
234 	int32_t get_max_unstall_level(TrainingAttribute, const TrainingSiteDescr&) const;
235 	void drop_unupgradable_soldiers(Game&);
236 	void drop_stalled_soldiers(Game&);
237 	Upgrade* get_upgrade(TrainingAttribute);
238 
239 	SoldierControl soldier_control_;
240 	/// Open requests for soldiers. The soldiers can be under way or unavailable
241 	Request* soldier_request_;
242 
243 	/** The soldiers currently at the training site*/
244 	std::vector<Soldier*> soldiers_;
245 
246 	/** Number of soldiers that should be trained concurrently.
247 	 * Equal or less to maximum number of soldiers supported by a training site.
248 	 * There is no guarantee there really are capacity_ soldiers in the
249 	 * building - some of them might still be under way or even not yet
250 	 * available*/
251 	Quantity capacity_;
252 
253 	/** True, \b always upgrade already experienced soldiers first, when possible
254 	 * False, \b always upgrade inexperienced soldiers first, when possible */
255 	bool build_heroes_;
256 
257 	std::vector<Upgrade> upgrades_;
258 	Upgrade* current_upgrade_;
259 
260 	ProgramResult result_;  /// The result of the last training program.
261 
262 	// These are used for kicking out soldiers prematurely
263 	static const uint32_t training_state_multiplier_;
264 	// Unuque key to address each training level of each war art
265 
266 	using TypeAndLevel = std::pair<TrainingAttribute, uint16_t>;
267 	// First entry is the "stallness", second is a bool
268 	using FailAndPresence = std::pair<uint16_t, uint8_t>;  // first might wrap in a long play..
269 	using TrainFailCount = std::map<TypeAndLevel, FailAndPresence>;
270 	TrainFailCount training_failure_count_;
271 	uint32_t max_stall_val_;
272 	// These are for soldier import.
273 	// If the training site can complete its job, or, in other words, soldiers leave
274 	// because of they are unupgradeable, then the training site tries to grab already-trained
275 	// folks in. If the site kicks soldiers off in the middle, it attempts to get poorly trained
276 	// replacements.
277 	//
278 	// Since ALL training sites do this, there needs to be a way to avoid deadlocks.
279 	// That makes this a bit messy. Sorry.
280 	//
281 	// If I was importing strong folks, and switch to weak ones, the switch only happens
282 	// after ongoing request is (partially) fulfilled. The other direction happens immediately.
283 	uint8_t highest_trainee_level_seen_;    // When requesting already-trained, start here.
284 	uint8_t latest_trainee_kickout_level_;  // If I cannot train, request soldiers that have been
285 	                                        // trainable
286 	uint8_t trainee_general_lower_bound_;   // This is the acceptance threshold currently in use.
287 	uint8_t repeated_layoff_ctr_;  // increases when soldier is prematurely releases, reset when
288 	                               // training succeeds.
289 	bool repeated_layoff_inc_;
290 	bool latest_trainee_was_kickout_;  // If soldier was not dropped, requesting new soldier.
291 	bool requesting_weak_trainees_;    // Value of the previous after incorporate.
292 	bool recent_capacity_increase_;    // If used explicitly asks for more folks
293 	const uint8_t kUpperBoundThreshold_ =
294 	   3;  // Higher value makes it less likely to get weak soldiers in.
295 	const uint32_t acceptance_threshold_timeout =
296 	   5555;  // Lower the bar after this many milliseconds.
297 	uint32_t
298 	   request_open_since_;  // Time units. If no soldiers appear, threshold is lowered after this.
299 	void init_kick_state(const TrainingAttribute&, const TrainingSiteDescr&);
300 };
301 
302 /**
303  * Note to be published when a soldier is leaving the training center
304  */
305 // A note we're using to notify the AI
306 struct NoteTrainingSiteSoldierTrained {
307 	CAN_BE_SENT_AS_NOTE(NoteId::TrainingSiteSoldierTrained)
308 
309 	// The trainingsite from where soldier is leaving.
310 	TrainingSite* ts;
311 
312 	// The player that owns the ttraining site.
313 	Player* player;
314 
NoteTrainingSiteSoldierTrainedNoteTrainingSiteSoldierTrained315 	NoteTrainingSiteSoldierTrained(TrainingSite* const init_ts, Player* init_player)
316 	   : ts(init_ts), player(init_player) {
317 	}
318 };
319 }  // namespace Widelands
320 
321 #endif  // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_TRAININGSITE_H
322