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