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 #include "logic/map_objects/tribes/trainingsite.h"
21 
22 #include <memory>
23 
24 #include "base/i18n.h"
25 #include "base/macros.h"
26 #include "base/wexception.h"
27 #include "economy/request.h"
28 #include "logic/editor_game_base.h"
29 #include "logic/game.h"
30 #include "logic/map_objects/tribes/production_program.h"
31 #include "logic/map_objects/tribes/soldier.h"
32 #include "logic/map_objects/tribes/tribe_descr.h"
33 #include "logic/map_objects/tribes/worker.h"
34 #include "logic/player.h"
35 
36 namespace Widelands {
37 
38 const uint32_t TrainingSite::training_state_multiplier_ = 12;
39 
40 /**
41  * The contents of 'table' are documented in
42  * /data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua
43  */
TrainingSiteDescr(const std::string & init_descname,const std::string & msgctxt,const LuaTable & table,const Tribes & tribes,const World & world)44 TrainingSiteDescr::TrainingSiteDescr(const std::string& init_descname,
45                                      const std::string& msgctxt,
46                                      const LuaTable& table,
47                                      const Tribes& tribes,
48                                      const World& world)
49    : ProductionSiteDescr(init_descname, msgctxt, MapObjectType::TRAININGSITE, table, tribes, world),
50      num_soldiers_(table.get_int("soldier_capacity")),
51      max_stall_(table.get_int("trainer_patience")),
52 
53      train_health_(false),
54      train_attack_(false),
55      train_defense_(false),
56      train_evade_(false),
57      min_health_(0),
58      min_attack_(0),
59      min_defense_(0),
60      min_evade_(0),
61      max_health_(0),
62      max_attack_(0),
63      max_defense_(0),
64      max_evade_(0) {
65 	// Read the range of levels that can update this building
66 	//  TODO(unknown): This is currently hardcoded to "soldier" but it should search for
67 	//  sections starting with the name of each soldier type.
68 	//  These sections also seem redundant. Eliminate them (having the
69 	//  programs should be enough).
70 	std::unique_ptr<LuaTable> items_table;
71 	if (table.has_key("soldier health")) {
72 		items_table = table.get_table("soldier health");
73 		train_health_ = true;
74 		min_health_ = items_table->get_int("min_level");
75 		max_health_ = items_table->get_int("max_level");
76 		add_training_inputs(*items_table, &food_health_, &weapons_health_);
77 	}
78 
79 	if (table.has_key("soldier attack")) {
80 		items_table = table.get_table("soldier attack");
81 		train_attack_ = true;
82 		min_attack_ = items_table->get_int("min_level");
83 		max_attack_ = items_table->get_int("max_level");
84 		add_training_inputs(*items_table, &food_attack_, &weapons_attack_);
85 	}
86 	if (table.has_key("soldier defense")) {
87 		items_table = table.get_table("soldier defense");
88 		train_defense_ = true;
89 		min_defense_ = items_table->get_int("min_level");
90 		max_defense_ = items_table->get_int("max_level");
91 		add_training_inputs(*items_table, &food_defense_, &weapons_defense_);
92 	}
93 	if (table.has_key("soldier evade")) {
94 		items_table = table.get_table("soldier evade");
95 		train_evade_ = true;
96 		min_evade_ = items_table->get_int("min_level");
97 		max_evade_ = items_table->get_int("max_level");
98 		add_training_inputs(*items_table, &food_evade_, &weapons_evade_);
99 	}
100 }
101 
102 /**
103  * Create a new training site
104  * \return  the new training site
105  */
create_object() const106 Building& TrainingSiteDescr::create_object() const {
107 	return *new TrainingSite(*this);
108 }
109 
110 /**
111  * \param at the attribute to investigate
112  * \return  the minimum level to which this building can downgrade a
113  * specified attribute
114  */
get_min_level(const TrainingAttribute at) const115 int32_t TrainingSiteDescr::get_min_level(const TrainingAttribute at) const {
116 	switch (at) {
117 	case TrainingAttribute::kHealth:
118 		return min_health_;
119 	case TrainingAttribute::kAttack:
120 		return min_attack_;
121 	case TrainingAttribute::kDefense:
122 		return min_defense_;
123 	case TrainingAttribute::kEvade:
124 		return min_evade_;
125 	case TrainingAttribute::kTotal:
126 		throw wexception("Unknown attribute value!");
127 	}
128 	NEVER_HERE();
129 }
130 
131 /**
132  * Returns the maximum level to which this building can upgrade a
133  * specified attribute
134  * \param at  the attribute to investigate
135  * \return  the maximum level to be attained at this site
136  */
get_max_level(const TrainingAttribute at) const137 int32_t TrainingSiteDescr::get_max_level(const TrainingAttribute at) const {
138 	switch (at) {
139 	case TrainingAttribute::kHealth:
140 		return max_health_;
141 	case TrainingAttribute::kAttack:
142 		return max_attack_;
143 	case TrainingAttribute::kDefense:
144 		return max_defense_;
145 	case TrainingAttribute::kEvade:
146 		return max_evade_;
147 	case TrainingAttribute::kTotal:
148 		throw wexception("Unknown attribute value!");
149 	}
150 	NEVER_HERE();
151 }
152 
153 /**
154  * Return the maximum level that can be trained, both by school type
155  * and resourcing.
156  */
get_max_unstall_level(const TrainingAttribute at,const TrainingSiteDescr & tsd) const157 int32_t TrainingSite::get_max_unstall_level(const TrainingAttribute at,
158                                             const TrainingSiteDescr& tsd) const {
159 	const int32_t max = tsd.get_max_level(at);
160 	const int32_t min = tsd.get_min_level(at);
161 	int32_t lev = min;
162 	int32_t rtv = min;
163 	while (lev < max) {
164 		TypeAndLevel train_tl(at, ++lev);
165 		TrainFailCount::const_iterator tstep = training_failure_count_.find(train_tl);
166 		if (max_stall_val_ > tstep->second.first) {
167 			rtv = lev;
168 		} else {
169 			lev = max;
170 		}
171 	}
172 
173 	return rtv;
174 }
175 
get_max_stall() const176 int32_t TrainingSiteDescr::get_max_stall() const {
177 	return max_stall_;
178 }
179 
add_training_inputs(const LuaTable & table,std::vector<std::vector<std::string>> * food,std::vector<std::string> * weapons)180 void TrainingSiteDescr::add_training_inputs(const LuaTable& table,
181                                             std::vector<std::vector<std::string>>* food,
182                                             std::vector<std::string>* weapons) {
183 
184 	if (table.has_key("food")) {
185 		std::unique_ptr<LuaTable> food_table = table.get_table("food");
186 		for (const int key : food_table->keys<int>()) {
187 			std::vector<std::string> food_vector;
188 			for (const std::string& food_item :
189 			     food_table->get_table(key)->array_entries<std::string>()) {
190 				food_vector.push_back(food_item);
191 			}
192 			food->push_back(food_vector);
193 		}
194 	}
195 	if (table.has_key("weapons")) {
196 		for (const std::string& weapon : table.get_table("weapons")->array_entries<std::string>()) {
197 			weapons->push_back(weapon);
198 		}
199 	}
200 }
201 
202 // TODO(sirver): This SoldierControl looks very similar to te one in
203 // MilitarySite. Pull out a class to reuse code.
present_soldiers() const204 std::vector<Soldier*> TrainingSite::SoldierControl::present_soldiers() const {
205 	return training_site_->soldiers_;
206 }
207 
stationed_soldiers() const208 std::vector<Soldier*> TrainingSite::SoldierControl::stationed_soldiers() const {
209 	return training_site_->soldiers_;
210 }
211 
min_soldier_capacity() const212 Quantity TrainingSite::SoldierControl::min_soldier_capacity() const {
213 	return 0;
214 }
max_soldier_capacity() const215 Quantity TrainingSite::SoldierControl::max_soldier_capacity() const {
216 	return training_site_->descr().get_max_number_of_soldiers();
217 }
soldier_capacity() const218 Quantity TrainingSite::SoldierControl::soldier_capacity() const {
219 	return training_site_->capacity_;
220 }
221 
set_soldier_capacity(Quantity const capacity)222 void TrainingSite::SoldierControl::set_soldier_capacity(Quantity const capacity) {
223 	assert(min_soldier_capacity() <= capacity);
224 	assert(capacity <= max_soldier_capacity());
225 	assert(training_site_->capacity_ != capacity);
226 	// Said in github issue #3869 discussion:
227 	//
228 	// > the problem will always be if the capacity of a training site will be
229 	// > increased AND you don't see soldiers leaving the warehouse while you
230 	// > know they are there you will be confused. So we should keep this very
231 	// > short anything more then 5 sec will cause confusion I believe.
232 	//
233 	// This piece implements this demand. If we add more control buttons to the
234 	// UI later, side-effects like this could go away.
235 	if (capacity > training_site_->capacity_) {
236 		// This is the capacity increased part from above.
237 		// Splitting a bit futher.
238 		if (0 == training_site_->capacity_ && 1 == capacity) {
239 			// If the site had a capacity of zero, then the player probably micromanages
240 			// and wants a partially trained soldier, if available. Resetting the state.
241 			training_site_->repeated_layoff_ctr_ = 0;
242 			training_site_->latest_trainee_was_kickout_ = false;
243 		} else {
244 			// Now the player just wants soldier. Any soldiers.
245 			training_site_->recent_capacity_increase_ = true;
246 		}
247 	}
248 	training_site_->capacity_ = capacity;
249 	training_site_->update_soldier_request(false);
250 }
251 
252 /**
253  * Drop a given soldier.
254  *
255  * 'Dropping' means releasing the soldier from the site. The soldier then
256  * becomes available to the economy.
257  *
258  * \note This is called from player commands, so we need to verify that the
259  * soldier is actually stationed here, without breaking anything if he isn't.
260  */
drop_soldier(Soldier & soldier)261 void TrainingSite::SoldierControl::drop_soldier(Soldier& soldier) {
262 	Game& game = dynamic_cast<Game&>(training_site_->get_owner()->egbase());
263 
264 	std::vector<Soldier*>::iterator it =
265 	   std::find(training_site_->soldiers_.begin(), training_site_->soldiers_.end(), &soldier);
266 	if (it == training_site_->soldiers_.end()) {
267 		training_site_->molog(
268 		   "TrainingSite::SoldierControl::drop_soldier: soldier not in training site");
269 		return;
270 	}
271 
272 	training_site_->soldiers_.erase(it);
273 
274 	soldier.reset_tasks(game);
275 	soldier.start_task_leavebuilding(game, true);
276 
277 	// Schedule, so that we can call new soldiers on next act()
278 	training_site_->schedule_act(game, 100);
279 	Notifications::publish(
280 	   NoteTrainingSiteSoldierTrained(training_site_, training_site_->get_owner()));
281 }
282 
incorporate_soldier(EditorGameBase & egbase,Soldier & s)283 int TrainingSite::SoldierControl::incorporate_soldier(EditorGameBase& egbase, Soldier& s) {
284 	if (s.get_location(egbase) != training_site_) {
285 		if (stationed_soldiers().size() + 1 > training_site_->descr().get_max_number_of_soldiers())
286 			return -1;
287 
288 		s.set_location(training_site_);
289 	}
290 
291 	// Bind the worker into this house, hide him on the map
292 	if (upcast(Game, game, &egbase))
293 		s.start_task_idle(*game, 0, -1);
294 
295 	// Make sure the request count is reduced or the request is deleted.
296 
297 	training_site_->update_soldier_request(true);
298 
299 	return 0;
300 }
301 
302 /*
303 =============================
304 
305 class TrainingSite
306 
307 =============================
308 */
309 
TrainingSite(const TrainingSiteDescr & d)310 TrainingSite::TrainingSite(const TrainingSiteDescr& d)
311    : ProductionSite(d),
312      soldier_control_(this),
313      soldier_request_(nullptr),
314      capacity_(descr().get_max_number_of_soldiers()),
315      build_heroes_(false),
316      result_(ProgramResult::kFailed) {
317 	set_soldier_control(&soldier_control_);
318 
319 	// Initialize this in the constructor so that loading code may
320 	// overwrite priorities.
321 	calc_upgrades();
322 	current_upgrade_ = nullptr;
323 	set_post_timer(6000);
324 	training_failure_count_.clear();
325 	max_stall_val_ = training_state_multiplier_ * d.get_max_stall();
326 	highest_trainee_level_seen_ = 1;
327 	latest_trainee_kickout_level_ = 1;
328 	latest_trainee_was_kickout_ = false;
329 	requesting_weak_trainees_ = false;
330 	request_open_since_ = 0;
331 	trainee_general_lower_bound_ = 2;
332 	repeated_layoff_ctr_ = 0;
333 	repeated_layoff_inc_ = false;
334 	recent_capacity_increase_ = false;
335 
336 	if (d.get_train_health())
337 		init_kick_state(TrainingAttribute::kHealth, d);
338 	if (d.get_train_attack())
339 		init_kick_state(TrainingAttribute::kAttack, d);
340 	if (d.get_train_defense())
341 		init_kick_state(TrainingAttribute::kDefense, d);
342 	if (d.get_train_evade())
343 		init_kick_state(TrainingAttribute::kEvade, d);
344 }
init_kick_state(const TrainingAttribute & art,const TrainingSiteDescr & d)345 void TrainingSite::init_kick_state(const TrainingAttribute& art, const TrainingSiteDescr& d) {
346 	// Now with kick-out state saving implemented, initializing is an overkill
347 	for (int t = d.get_min_level(art); t <= d.get_max_level(art); t++)
348 		training_attempted(art, t);
349 }
350 
351 /**
352  * Setup the building and request soldiers
353  */
init(EditorGameBase & egbase)354 bool TrainingSite::init(EditorGameBase& egbase) {
355 	ProductionSite::init(egbase);
356 
357 	upcast(Game, game, &egbase);
358 
359 	for (Soldier* soldier : soldiers_) {
360 		soldier->set_location_initially(*this);
361 		assert(!soldier->get_state());  //  Should be newly created.
362 
363 		if (game) {
364 			soldier->start_task_idle(*game, 0, -1);
365 		}
366 	}
367 	update_soldier_request(false);
368 	return true;
369 }
370 
371 /**
372  * Change the economy this site belongs to.
373  * \par e  The new economy. Can be 0 (unconnected buildings have no economy).
374  * \note the worker (but not the soldiers) is dealt with in the
375  * PlayerImmovable code.
376  */
set_economy(Economy * e,WareWorker type)377 void TrainingSite::set_economy(Economy* e, WareWorker type) {
378 	ProductionSite::set_economy(e, type);
379 
380 	if (soldier_request_ && type == soldier_request_->get_type())
381 		soldier_request_->set_economy(e);
382 }
383 
384 /**
385  * Cleanup after a Training site is removed
386  *
387  * Cancel all soldier requests and release all soldiers
388  */
cleanup(EditorGameBase & egbase)389 void TrainingSite::cleanup(EditorGameBase& egbase) {
390 	delete soldier_request_;
391 	soldier_request_ = nullptr;
392 
393 	ProductionSite::cleanup(egbase);
394 }
395 
add_worker(Worker & w)396 void TrainingSite::add_worker(Worker& w) {
397 	ProductionSite::add_worker(w);
398 
399 	if (upcast(Soldier, soldier, &w)) {
400 		// Note that the given Soldier might already be in the array
401 		// for loadgames.
402 		if (std::find(soldiers_.begin(), soldiers_.end(), soldier) == soldiers_.end())
403 			soldiers_.push_back(soldier);
404 
405 		if (upcast(Game, game, &get_owner()->egbase()))
406 			schedule_act(*game, 100);
407 	}
408 }
409 
remove_worker(Worker & w)410 void TrainingSite::remove_worker(Worker& w) {
411 	upcast(Game, game, &get_owner()->egbase());
412 
413 	if (upcast(Soldier, soldier, &w)) {
414 		std::vector<Soldier*>::iterator const it =
415 		   std::find(soldiers_.begin(), soldiers_.end(), soldier);
416 		if (it != soldiers_.end()) {
417 			soldiers_.erase(it);
418 
419 			if (game)
420 				schedule_act(*game, 100);
421 		}
422 	}
423 
424 	ProductionSite::remove_worker(w);
425 }
426 
427 /**
428  * Request soldiers up to capacity, or let go of surplus soldiers.
429  *
430  * Now, we attempt to intelligently select most suitable soldiers
431  * (either already somwhat trained, or if training stalls, less
432  * trained ones). If no luck, the criteria is made relaxed until
433  * somebody shows up.
434  */
update_soldier_request(bool did_incorporate)435 void TrainingSite::update_soldier_request(bool did_incorporate) {
436 	Game* game = get_owner() ? dynamic_cast<Game*>(&(get_owner()->egbase())) : nullptr;
437 	bool rebuild_request = false;
438 	bool need_more_soldiers = false;
439 	uint32_t dynamic_timeout = acceptance_threshold_timeout;
440 	uint8_t trainee_general_upper_bound = std::numeric_limits<uint8_t>::max() - 1;
441 	bool limit_upper_bound = false;
442 
443 	if (soldiers_.size() < capacity_) {
444 		// If not full, I need more soldiers.
445 		need_more_soldiers = true;
446 	}
447 
448 	// Usually, we prefer already partially trained soldiers here.
449 	// In some conditions, this can lead to same soldiers walking back and forth.
450 	// this tries to break that cycle. The goal is that this code only kicks in
451 	// in those specific conditions. This if statement is true if we repeatedly
452 	// incorporate and release soldiers, without training them at all.
453 	if (kUpperBoundThreshold_ < repeated_layoff_ctr_) {
454 		if (repeated_layoff_ctr_ > kUpperBoundThreshold_ + highest_trainee_level_seen_) {
455 			repeated_layoff_ctr_ = 0;
456 		} else {
457 			trainee_general_upper_bound =
458 			   kUpperBoundThreshold_ + highest_trainee_level_seen_ - repeated_layoff_ctr_;
459 			limit_upper_bound = true;
460 		}
461 		if (did_incorporate) {
462 			rebuild_request = need_more_soldiers;
463 		}
464 	}
465 	// This boolean ensures that kicking out many soldiers in a row does not count as
466 	// soldiers entering and leaving without training. We need to repeatedly incorporate
467 	// and release for the last resort to kick in. I need this boolean, to detect that
468 	// a soldier was incorporated between soldiers leaving.
469 	if (did_incorporate) {
470 		repeated_layoff_inc_ = true;
471 	}
472 
473 	const uint32_t timeofgame = game ? game->get_gametime() : 0;
474 
475 	if (did_incorporate && latest_trainee_was_kickout_ != requesting_weak_trainees_) {
476 		// If type of desired recruits has been changed, the request is rebuild after incorporate
477 		// even if (wrong/old) type recruits are on the way.
478 		rebuild_request = need_more_soldiers;
479 		requesting_weak_trainees_ = latest_trainee_was_kickout_;
480 	}
481 
482 	if (did_incorporate) {
483 		// If we got somebody in, lets become picky again.
484 		// Request is not regenerated at this point. Should it?
485 		if (requesting_weak_trainees_) {
486 			trainee_general_lower_bound_ = latest_trainee_kickout_level_;
487 		} else {
488 			trainee_general_lower_bound_ = static_cast<uint8_t>(std::max<unsigned>(
489 			   1, (std::min<unsigned>(highest_trainee_level_seen_,
490 			                          (static_cast<unsigned>(trainee_general_lower_bound_) + 1 +
491 			                           static_cast<unsigned>(highest_trainee_level_seen_)) /
492 			                             2))));
493 		}
494 		request_open_since_ = timeofgame;
495 	}
496 	if (soldier_request_ && need_more_soldiers) {
497 		if ((!requesting_weak_trainees_) && (!limit_upper_bound)) {
498 			// If requesting strong folks, the acceptance time can sometimes grow unbearable large
499 			// without this.
500 			// In request weak mode, resources are typically thin and this harms less, In addition,
501 			// the starting value tends to be much smaller in request-weak mode.
502 			dynamic_timeout =
503 			   acceptance_threshold_timeout /
504 			   std::max<uint32_t>(1, static_cast<unsigned>(trainee_general_lower_bound_));
505 			// In the special case of training not working at all, there is no need for this speedup
506 			// (hence the 2nd check)
507 		}
508 		if (0 == soldier_request_->get_num_transfers() &&
509 		    timeofgame > request_open_since_ + dynamic_timeout) {
510 			// Timeout: We have been asking for certain type of soldiers, nobody is answering the call.
511 			// Relaxing the criteria (and thus rebuild the request)
512 			rebuild_request = need_more_soldiers;
513 			if (0 < trainee_general_lower_bound_) {
514 				trainee_general_lower_bound_--;
515 				dynamic_timeout =
516 				   acceptance_threshold_timeout /
517 				   std::max<uint32_t>(1, static_cast<unsigned>(trainee_general_lower_bound_));
518 			} else if (requesting_weak_trainees_) {
519 				// If requesting weak trainees, and no people show up:
520 				// set the state back to request_strong, which will allow everybody in
521 				// when threshold is zero. Hopefully, you are fine with this misuse
522 				// of variable names.
523 				requesting_weak_trainees_ = false;
524 				latest_trainee_was_kickout_ = false;
525 			}
526 			if (kUpperBoundThreshold_ <= repeated_layoff_ctr_ && soldiers_.empty()) {
527 				// Repeated layoff ctr breaks the cycle when same few soldiers pendle back and forth.
528 				// If no soldiers are arriving and none are present, this cannot be the case.
529 				// Trainingsites without soldiers for long confuse players, thus retracting.
530 				repeated_layoff_ctr_ = 0;
531 				requesting_weak_trainees_ = false;
532 				latest_trainee_was_kickout_ = false;
533 			}
534 		}
535 	}
536 
537 	if (!soldier_request_) {
538 		rebuild_request = need_more_soldiers;
539 	}
540 
541 	if (rebuild_request) {
542 		// I've changed my acceptance criteria
543 		if (soldier_request_) {
544 			delete soldier_request_;
545 			soldier_request_ = nullptr;
546 		}
547 
548 		assert(need_more_soldiers);
549 		if (recent_capacity_increase_) {
550 			// See comments in TrainingSite::SoldierControl::set_soldier_capacity() for details
551 			// In short: If user interacts, I accept anybody regardless of state.
552 			requesting_weak_trainees_ = false;
553 			limit_upper_bound = false;
554 			trainee_general_lower_bound_ = 0;
555 			recent_capacity_increase_ = false;
556 		}
557 
558 		soldier_request_ = new Request(
559 		   *this, owner().tribe().soldier(), TrainingSite::request_soldier_callback, wwWORKER);
560 
561 		RequireOr r;
562 
563 		// set requirements to match this site
564 		if (descr().get_train_attack()) {
565 			// In "request weak trainees" mode, we ask for soldiers that are below stalled level
566 			if (requesting_weak_trainees_) {
567 				r.add(RequireAttribute(TrainingAttribute::kAttack,
568 				                       descr().get_min_level(TrainingAttribute::kAttack),
569 				                       get_max_unstall_level(TrainingAttribute::kAttack, descr())));
570 			} else {
571 				r.add(RequireAttribute(TrainingAttribute::kAttack,
572 				                       descr().get_min_level(TrainingAttribute::kAttack),
573 				                       descr().get_max_level(TrainingAttribute::kAttack)));
574 			}
575 		}
576 		if (descr().get_train_defense()) {
577 			if (requesting_weak_trainees_) {
578 				r.add(RequireAttribute(TrainingAttribute::kDefense,
579 				                       descr().get_min_level(TrainingAttribute::kDefense),
580 				                       get_max_unstall_level(TrainingAttribute::kDefense, descr())));
581 			} else {
582 				r.add(RequireAttribute(TrainingAttribute::kDefense,
583 				                       descr().get_min_level(TrainingAttribute::kDefense),
584 				                       descr().get_max_level(TrainingAttribute::kDefense)));
585 			}
586 		}
587 		if (descr().get_train_evade()) {
588 			if (requesting_weak_trainees_) {
589 				r.add(RequireAttribute(TrainingAttribute::kEvade,
590 				                       descr().get_min_level(TrainingAttribute::kEvade),
591 				                       get_max_unstall_level(TrainingAttribute::kEvade, descr())));
592 			} else {
593 				r.add(RequireAttribute(TrainingAttribute::kEvade,
594 				                       descr().get_min_level(TrainingAttribute::kEvade),
595 				                       descr().get_max_level(TrainingAttribute::kEvade)));
596 			}
597 		}
598 		if (descr().get_train_health()) {
599 			if (requesting_weak_trainees_) {
600 				r.add(RequireAttribute(TrainingAttribute::kHealth,
601 				                       descr().get_min_level(TrainingAttribute::kHealth),
602 				                       get_max_unstall_level(TrainingAttribute::kHealth, descr())));
603 			} else {
604 				r.add(RequireAttribute(TrainingAttribute::kHealth,
605 				                       descr().get_min_level(TrainingAttribute::kHealth),
606 				                       descr().get_max_level(TrainingAttribute::kHealth)));
607 			}
608 		}
609 
610 		// The above selects everybody that could be trained here. If I am picky, then also exclude
611 		// those
612 		// that I could train but do not wish to spend time & resources on.
613 		if (limit_upper_bound) {
614 			RequireAnd qr;
615 			qr.add(RequireAttribute(TrainingAttribute::kTotal, 0, trainee_general_upper_bound));
616 			qr.add(r);
617 			soldier_request_->set_requirements(qr);
618 		} else if (0 < trainee_general_lower_bound_) {
619 			RequireAnd qr;
620 			qr.add(RequireAttribute(TrainingAttribute::kTotal, trainee_general_lower_bound_ + 1,
621 			                        std::numeric_limits<uint8_t>::max() - 1));
622 			qr.add(r);
623 			soldier_request_->set_requirements(qr);
624 			if (game) {
625 				schedule_act(*game, 1 + dynamic_timeout);
626 			}
627 		} else {
628 			soldier_request_->set_requirements(r);
629 		}
630 		soldier_request_->set_count(capacity_ - soldiers_.size());
631 		request_open_since_ = timeofgame;
632 
633 	} else if (!need_more_soldiers) {
634 		delete soldier_request_;
635 		soldier_request_ = nullptr;
636 
637 		while (soldiers_.size() > capacity_) {
638 			soldier_control_.drop_soldier(**soldiers_.rbegin());
639 		}
640 	} else {
641 		soldier_request_->set_count(capacity_ - soldiers_.size());
642 	}
643 }
644 
645 /**
646  * Soldier callback. Since the soldier was already added via add_worker,
647  * we only need to update the request structure.
648  */
request_soldier_callback(Game & game,Request & rq,DescriptionIndex,Worker * const w,PlayerImmovable & target)649 void TrainingSite::request_soldier_callback(Game& game,
650 #ifndef NDEBUG
651                                             Request& rq,
652 #else
653                                             Request&,
654 #endif
655                                             DescriptionIndex,
656                                             Worker* const w,
657                                             PlayerImmovable& target) {
658 	TrainingSite& tsite = dynamic_cast<TrainingSite&>(target);
659 	Soldier& s = dynamic_cast<Soldier&>(*w);
660 
661 	assert(s.get_location(game) == &tsite);
662 	assert(tsite.soldier_request_ == &rq);
663 
664 	tsite.soldier_control_.incorporate_soldier(game, s);
665 }
666 
667 /**
668  * Drop all the soldiers that can not be upgraded further at this building.
669  */
drop_unupgradable_soldiers(Game &)670 void TrainingSite::drop_unupgradable_soldiers(Game&) {
671 	std::vector<Soldier*> droplist;
672 
673 	for (uint32_t i = 0; i < soldiers_.size(); ++i) {
674 		std::vector<Upgrade>::iterator it = upgrades_.begin();
675 		for (; it != upgrades_.end(); ++it) {
676 			int32_t level = soldiers_[i]->get_level(it->attribute);
677 			if (level >= it->min && level <= it->max)
678 				break;
679 		}
680 
681 		if (it == upgrades_.end())
682 			droplist.push_back(soldiers_[i]);
683 	}
684 
685 	// Drop soldiers only now, so that changes in the soldiers array don't
686 	// mess things up
687 	for (Soldier* soldier : droplist) {
688 		uint8_t level = soldier->get_level(TrainingAttribute::kTotal);
689 		if (level > highest_trainee_level_seen_) {
690 			highest_trainee_level_seen_ = level;
691 		}
692 
693 		soldier_control_.drop_soldier(*soldier);
694 		repeated_layoff_ctr_ = 0;  // redundant, but safe (also reset whenever level increases)
695 		if (latest_trainee_was_kickout_) {
696 			// If I am calling in weaklings: Stop that. Immediately.
697 			latest_trainee_was_kickout_ = false;
698 			update_soldier_request(true);
699 		}
700 		repeated_layoff_inc_ = false;
701 	}
702 }
703 
704 /**
705  * Drop all the soldiers that can not be upgraded further at this level of resourcing.
706  *
707  */
drop_stalled_soldiers(Game &)708 void TrainingSite::drop_stalled_soldiers(Game&) {
709 	Soldier* soldier_to_drop = nullptr;
710 	uint8_t highest_soldier_level_seen = 0;
711 
712 	for (uint32_t i = 0; i < soldiers_.size(); ++i) {
713 		uint8_t this_soldier_level = soldiers_[i]->get_level(TrainingAttribute::kTotal);
714 
715 		bool this_soldier_is_safe = false;
716 		if (this_soldier_level <= highest_soldier_level_seen) {
717 			// Skip the innermost loop for soldiers that would not be kicked out anyway.
718 			// level-zero soldiers are excepted from kick-out implicitly. This is intentional.
719 			this_soldier_is_safe = true;
720 		} else {
721 			for (const Upgrade& upgrade : upgrades_) {
722 				if (!this_soldier_is_safe) {
723 					// Soldier is safe, if he:
724 					//  - is below maximum, and
725 					//  - is not in a stalled state
726 					// Check done separately for each art.
727 					int32_t level = soldiers_[i]->get_level(upgrade.attribute);
728 
729 					// Below maximum -check
730 					if (level > upgrade.max) {
731 						continue;
732 					}
733 
734 					TypeAndLevel train_tl(upgrade.attribute, level);
735 					TrainFailCount::iterator tstep = training_failure_count_.find(train_tl);
736 					if (tstep == training_failure_count_.end()) {
737 						log("\nTrainingSite::drop_stalled_soldiers: ");
738 						log("training step %d,%d not found in this school!\n",
739 						    static_cast<unsigned int>(upgrade.attribute), level);
740 						break;
741 					}
742 
743 					tstep->second.second = 1;  // a soldier is present at this level
744 
745 					// Stalled state -check
746 					if (max_stall_val_ > tstep->second.first) {
747 						this_soldier_is_safe = true;
748 						break;
749 					}
750 				}
751 			}
752 		}
753 		if (!this_soldier_is_safe) {
754 			// Make this soldier a kick-out candidate
755 			soldier_to_drop = soldiers_[i];
756 			highest_soldier_level_seen = this_soldier_level;
757 		}
758 	}
759 
760 	// Finally drop the soldier.
761 	if (nullptr != soldier_to_drop) {
762 		log("TrainingSite::drop_stalled_soldiers: Kicking somebody out.\n");
763 		uint8_t level = soldier_to_drop->get_level(TrainingAttribute::kTotal);
764 		if (level > highest_trainee_level_seen_) {
765 			highest_trainee_level_seen_ = level;
766 		}
767 		latest_trainee_kickout_level_ = level;
768 		soldier_control_.drop_soldier(*soldier_to_drop);
769 		latest_trainee_was_kickout_ = true;
770 		// We can enter into state where same soldiers repeatedly enter the site
771 		// even if they cannot be promited (lack of gold, lack of an equipmentsmith
772 		// of some kind or so). The repeated_layoff_ctr_ works around that.
773 		//
774 		// Only repeated drops with incorporating new soldiers in between causes this to happen!
775 		if (std::numeric_limits<uint8_t>::max() - 1 > repeated_layoff_ctr_ && repeated_layoff_inc_) {
776 			repeated_layoff_ctr_++;
777 			repeated_layoff_inc_ = false;
778 		}
779 	}
780 }
781 
create_building_settings() const782 const BuildingSettings* TrainingSite::create_building_settings() const {
783 	TrainingsiteSettings* settings = new TrainingsiteSettings(descr(), owner().tribe());
784 	settings->apply(*ProductionSite::create_building_settings());
785 	settings->desired_capacity =
786 	   std::min(settings->max_capacity, soldier_control_.soldier_capacity());
787 	return settings;
788 }
789 
790 /**
791  * In addition to advancing the program, update soldier status.
792  */
act(Game & game,uint32_t const data)793 void TrainingSite::act(Game& game, uint32_t const data) {
794 	// unit of gametime is [ms].
795 	ProductionSite::act(game, data);
796 	update_soldier_request(false);
797 }
798 
program_end(Game & game,ProgramResult const result)799 void TrainingSite::program_end(Game& game, ProgramResult const result) {
800 	result_ = result;
801 	ProductionSite::program_end(game, result);
802 	// For unknown reasons sometimes there is a fully upgraded soldier
803 	// that failed to be send away, so at the end of this function
804 	// we test for such soldiers, unless another drop_soldiers
805 	// function were run
806 	bool leftover_soldiers_check = true;
807 
808 	if (current_upgrade_) {
809 		if (result_ == ProgramResult::kCompleted) {
810 			drop_unupgradable_soldiers(game);
811 			leftover_soldiers_check = false;
812 			current_upgrade_->lastsuccess = true;
813 			current_upgrade_->failures = 0;
814 
815 			// I try to already somewhat trained soldiers here, except when
816 			// no training happens. Now some training has happened, hence zero.
817 			// read in update_soldier_request
818 			repeated_layoff_ctr_ = 0;
819 			repeated_layoff_inc_ = false;
820 		} else {
821 			current_upgrade_->failures++;
822 			drop_stalled_soldiers(game);
823 			leftover_soldiers_check = false;
824 		}
825 		current_upgrade_ = nullptr;
826 	}
827 
828 	if (leftover_soldiers_check) {
829 		drop_unupgradable_soldiers(game);
830 	}
831 
832 	training_done();
833 }
834 
835 /**
836  * Find and start the next training program.
837  *
838  * Prioritize such that if UpgradeA.prio is twice UpgradeB.prio, then
839  * start_upgrade will be called twice as often for UpgradeA.
840  * If all priorities are zero, nothing will happen.
841  */
find_and_start_next_program(Game & game)842 void TrainingSite::find_and_start_next_program(Game& game) {
843 	for (;;) {
844 		uint32_t maxprio = 0;
845 		uint32_t maxcredit = 0;
846 
847 		for (Upgrade& upgrade : upgrades_) {
848 			if (upgrade.credit >= 10) {
849 				upgrade.credit -= 10;
850 				return start_upgrade(game, upgrade);
851 			}
852 
853 			if (maxprio < upgrade.prio)
854 				maxprio = upgrade.prio;
855 			if (maxcredit < upgrade.credit)
856 				maxcredit = upgrade.credit;
857 		}
858 
859 		if (maxprio == 0) {
860 			return program_start(game, "sleep");
861 		}
862 
863 		uint32_t const multiplier = 1 + (10 - maxcredit) / maxprio;
864 
865 		for (Upgrade& upgrade : upgrades_) {
866 			upgrade.credit += multiplier * upgrade.prio;
867 		}
868 	}
869 }
870 
871 /**
872  * The prioritizer decided that the given type of upgrade should run.
873  * Let's do our worst.
874  */
start_upgrade(Game & game,Upgrade & upgrade)875 void TrainingSite::start_upgrade(Game& game, Upgrade& upgrade) {
876 	int32_t minlevel = upgrade.max;
877 	int32_t maxlevel = upgrade.min;
878 
879 	for (Soldier* soldier : soldiers_) {
880 		int32_t const level = soldier->get_level(upgrade.attribute);
881 
882 		if (level > upgrade.max || level < upgrade.min)
883 			continue;
884 		if (level < minlevel)
885 			minlevel = level;
886 		if (level > maxlevel)
887 			maxlevel = level;
888 	}
889 
890 	if (minlevel > maxlevel)
891 		return program_start(game, "sleep");
892 
893 	int32_t level;
894 
895 	if (upgrade.lastsuccess || upgrade.lastattempt < 0) {
896 		// Start greedily on the first ever attempt, and restart greedily
897 		// after a sucessful upgrade
898 		if (build_heroes_)
899 			level = maxlevel;
900 		else
901 			level = minlevel;
902 	} else {
903 		// The last attempt wasn't successful;
904 		// This happens e.g. when lots of low-level soldiers are present,
905 		// but the prerequisites for improving them aren't.
906 		if (build_heroes_) {
907 			level = upgrade.lastattempt - 1;
908 			if (level < minlevel)
909 				level = maxlevel;
910 		} else {
911 			level = upgrade.lastattempt + 1;
912 			if (level > maxlevel)
913 				level = minlevel;
914 		}
915 	}
916 
917 	current_upgrade_ = &upgrade;
918 	upgrade.lastattempt = level;
919 	upgrade.lastsuccess = false;
920 
921 	return program_start(game, (boost::format("%s%i") % upgrade.prefix.c_str() % level).str());
922 }
923 
get_upgrade(TrainingAttribute const atr)924 TrainingSite::Upgrade* TrainingSite::get_upgrade(TrainingAttribute const atr) {
925 	for (Upgrade& upgrade : upgrades_) {
926 		if (upgrade.attribute == atr) {
927 			return &upgrade;
928 		}
929 	}
930 	return nullptr;
931 }
932 
933 /**
934  * Gets the priority of given attribute
935  */
get_pri(TrainingAttribute atr)936 int32_t TrainingSite::get_pri(TrainingAttribute atr) {
937 	for (const Upgrade& upgrade : upgrades_) {
938 		if (upgrade.attribute == atr) {
939 			return upgrade.prio;
940 		}
941 	}
942 	return 0;
943 }
944 
945 /**
946  * Sets the priority of given attribute
947  */
set_pri(TrainingAttribute atr,int32_t prio)948 void TrainingSite::set_pri(TrainingAttribute atr, int32_t prio) {
949 	if (prio < 0)
950 		prio = 0;
951 
952 	for (Upgrade& upgrade : upgrades_) {
953 		if (upgrade.attribute == atr) {
954 			upgrade.prio = prio;
955 			return;
956 		}
957 	}
958 }
959 
960 /**
961  * Only called from \ref calc_upgrades
962  */
add_upgrade(TrainingAttribute const atr,const std::string & prefix)963 void TrainingSite::add_upgrade(TrainingAttribute const atr, const std::string& prefix) {
964 	Upgrade u;
965 	u.attribute = atr;
966 	u.prefix = prefix;
967 	u.min = descr().get_min_level(atr);
968 	u.max = descr().get_max_level(atr);
969 	u.prio = 6;
970 	u.credit = 0;
971 	u.lastattempt = -1;
972 	u.lastsuccess = false;
973 	u.failures = 0;
974 	upgrades_.push_back(u);
975 }
976 
977 /**
978  * Called once at initialization to populate \ref upgrades_.
979  */
calc_upgrades()980 void TrainingSite::calc_upgrades() {
981 	assert(upgrades_.empty());
982 
983 	//  TODO(unknown): This is currently hardcoded for "soldier" but it should allow any
984 	//  soldier type name.
985 	if (descr().get_train_health())
986 		add_upgrade(TrainingAttribute::kHealth, "upgrade_soldier_health_");
987 	if (descr().get_train_attack())
988 		add_upgrade(TrainingAttribute::kAttack, "upgrade_soldier_attack_");
989 	if (descr().get_train_defense())
990 		add_upgrade(TrainingAttribute::kDefense, "upgrade_soldier_defense_");
991 	if (descr().get_train_evade())
992 		add_upgrade(TrainingAttribute::kEvade, "upgrade_soldier_evade_");
993 }
994 
training_attempted(TrainingAttribute type,uint32_t level)995 void TrainingSite::training_attempted(TrainingAttribute type, uint32_t level) {
996 	TypeAndLevel key(type, level);
997 	if (training_failure_count_.find(key) == training_failure_count_.end())
998 		training_failure_count_[key] = std::make_pair(training_state_multiplier_, 0);
999 	else
1000 		training_failure_count_[key].first += training_state_multiplier_;
1001 }
1002 
1003 /**
1004  * Called whenever it was possible to promote another guy
1005  */
1006 
training_successful(TrainingAttribute type,uint32_t level)1007 void TrainingSite::training_successful(TrainingAttribute type, uint32_t level) {
1008 	TypeAndLevel key(type, level);
1009 	// Here I assume that key exists: training has been attempted before it can succeed.
1010 	training_failure_count_[key].first = 0;
1011 }
1012 
training_done()1013 void TrainingSite::training_done() {
1014 	for (auto& fail_and_presence : training_failure_count_) {
1015 		// If a soldier is present at this training level and site is running, deteoriate
1016 		if (fail_and_presence.second.second && (!is_stopped())) {
1017 			fail_and_presence.second.first++;
1018 			fail_and_presence.second.second = 0;
1019 		} else if (0 < fail_and_presence.second.first) {  // If no soldier, let's become optimistic
1020 			fail_and_presence.second.first--;
1021 		}
1022 	}
1023 }
1024 }  // namespace Widelands
1025