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_PRODUCTIONSITE_H 21 #define WL_LOGIC_MAP_OBJECTS_TRIBES_PRODUCTIONSITE_H 22 23 #include <memory> 24 25 #include "base/macros.h" 26 #include "logic/map_objects/tribes/bill_of_materials.h" 27 #include "logic/map_objects/tribes/building.h" 28 #include "logic/map_objects/tribes/production_program.h" 29 #include "logic/map_objects/tribes/program_result.h" 30 #include "scripting/lua_table.h" 31 32 namespace Widelands { 33 34 class Request; 35 class Soldier; 36 class WorkerDescr; 37 38 enum class FailNotificationType { kDefault, kFull }; 39 40 /** 41 * Every building that is part of the economics system is a production site. 42 * 43 * A production site has a worker. 44 * A production site can have one (or more) output wares types (in theory it 45 * should be possible to burn wares for some virtual result such as "mana", or 46 * maybe even just for the fun of it, although that's not planned). 47 * A production site can have one (or more) input wares types. Every input 48 * wares type has an associated store. 49 */ 50 class ProductionSiteDescr : public BuildingDescr { 51 public: 52 friend struct ProductionProgram; // To add animations 53 54 ProductionSiteDescr(const std::string& init_descname, 55 const std::string& msgctxt, 56 MapObjectType type, 57 const LuaTable& t, 58 const Tribes& tribes, 59 const World& world); 60 ProductionSiteDescr(const std::string& init_descname, 61 const std::string& msgctxt, 62 const LuaTable& t, 63 const Tribes& tribes, 64 const World& world); 65 66 Building& create_object() const override; 67 68 // List of wares to register having economy checks. Parsed by the tribes during postload and must 69 // be nullptr after loading has finished 70 std::set<DescriptionIndex>* ware_demand_checks() const; 71 // List of workers to register having economy checks. Parsed by the tribes during postload and 72 // must be nullptr after loading has finished 73 std::set<DescriptionIndex>* worker_demand_checks() const; 74 // Clear ware and worker demand check info 75 void clear_demand_checks(); 76 nr_working_positions()77 uint32_t nr_working_positions() const { 78 uint32_t result = 0; 79 for (const auto& working_pos : working_positions()) { 80 result += working_pos.second; 81 } 82 return result; 83 } working_positions()84 const BillOfMaterials& working_positions() const { 85 return working_positions_; 86 } is_output_ware_type(const DescriptionIndex & i)87 bool is_output_ware_type(const DescriptionIndex& i) const { 88 return output_ware_types_.count(i); 89 } is_output_worker_type(const DescriptionIndex & i)90 bool is_output_worker_type(const DescriptionIndex& i) const { 91 return output_worker_types_.count(i); 92 } input_wares()93 const BillOfMaterials& input_wares() const { 94 return input_wares_; 95 } input_workers()96 const BillOfMaterials& input_workers() const { 97 return input_workers_; 98 } 99 using Output = std::set<DescriptionIndex>; output_ware_types()100 const Output& output_ware_types() const { 101 return output_ware_types_; 102 } output_worker_types()103 const Output& output_worker_types() const { 104 return output_worker_types_; 105 } 106 const ProductionProgram* get_program(const std::string&) const; 107 using Programs = std::map<std::string, std::unique_ptr<ProductionProgram>>; programs()108 const Programs& programs() const { 109 return programs_; 110 } 111 out_of_resource_title()112 const std::string& out_of_resource_title() const { 113 return out_of_resource_title_; 114 } 115 out_of_resource_heading()116 const std::string& out_of_resource_heading() const { 117 return out_of_resource_heading_; 118 } 119 out_of_resource_message()120 const std::string& out_of_resource_message() const { 121 return out_of_resource_message_; 122 } 123 resource_not_needed_message()124 const std::string& resource_not_needed_message() const { 125 return resource_not_needed_message_; 126 } 127 out_of_resource_productivity_threshold()128 uint32_t out_of_resource_productivity_threshold() const { 129 return out_of_resource_productivity_threshold_; 130 } 131 highlight_overlapping_workarea_for(const std::string & n,bool * positive)132 bool highlight_overlapping_workarea_for(const std::string& n, bool* positive) const { 133 const auto it = highlight_overlapping_workarea_for_.find(n); 134 if (it == highlight_overlapping_workarea_for_.end()) { 135 return false; 136 } else { 137 *positive = it->second; 138 return true; 139 } 140 } 141 get_highlight_overlapping_workarea_for()142 const std::map<std::string, bool>& get_highlight_overlapping_workarea_for() const { 143 return highlight_overlapping_workarea_for_; 144 } 145 146 private: 147 std::unique_ptr<std::set<DescriptionIndex>> ware_demand_checks_; 148 std::unique_ptr<std::set<DescriptionIndex>> worker_demand_checks_; 149 BillOfMaterials working_positions_; 150 BillOfMaterials input_wares_; 151 BillOfMaterials input_workers_; 152 Output output_ware_types_; 153 Output output_worker_types_; 154 Programs programs_; 155 std::string out_of_resource_title_; 156 std::string out_of_resource_heading_; 157 std::string out_of_resource_message_; 158 std::string resource_not_needed_message_; 159 int out_of_resource_productivity_threshold_; 160 std::map<std::string, bool> highlight_overlapping_workarea_for_; 161 162 DISALLOW_COPY_AND_ASSIGN(ProductionSiteDescr); 163 }; 164 165 class ProductionSite : public Building { 166 friend class MapBuildingdataPacket; 167 friend struct ProductionProgram::ActReturn; 168 friend struct ProductionProgram::ActReturn::WorkersNeedExperience; 169 friend struct ProductionProgram::ActCall; 170 friend struct ProductionProgram::ActCallWorker; 171 friend struct ProductionProgram::ActSleep; 172 friend struct ProductionProgram::ActAnimate; 173 friend struct ProductionProgram::ActConsume; 174 friend struct ProductionProgram::ActProduce; 175 friend struct ProductionProgram::ActRecruit; 176 friend struct ProductionProgram::ActMine; 177 friend struct ProductionProgram::ActCheckSoldier; 178 friend struct ProductionProgram::ActTrain; 179 friend struct ProductionProgram::ActPlaySound; 180 friend struct ProductionProgram::ActConstruct; 181 MO_DESCR(ProductionSiteDescr) 182 183 public: 184 explicit ProductionSite(const ProductionSiteDescr& descr); 185 ~ProductionSite() override; 186 187 void log_general_info(const EditorGameBase&) const override; 188 is_stopped()189 bool is_stopped() const { 190 return is_stopped_; 191 } 192 void set_stopped(bool); 193 194 struct WorkingPosition { 195 WorkingPosition(Request* const wr = nullptr, Worker* const w = nullptr) worker_requestWorkingPosition196 : worker_request(wr), worker(w) { 197 } 198 Request* worker_request; 199 Worker* worker; 200 }; 201 working_positions()202 WorkingPosition const* working_positions() const { 203 return working_positions_; 204 } 205 206 virtual bool has_workers(DescriptionIndex targetSite, Game& game); get_statistics_percent()207 uint8_t get_statistics_percent() { 208 return last_stat_percent_ / 10; 209 } 210 211 // receives the duration of the last period and the result (true if something was produced) 212 // and sets actual_percent_ to new value 213 void update_actual_statistics(uint32_t, bool); 214 get_actual_statistics()215 uint8_t get_actual_statistics() { 216 return actual_percent_ / 10; 217 } 218 production_result()219 const std::string& production_result() const { 220 return production_result_; 221 } 222 223 // Production and worker programs set this to explain the current 224 // state of the production. This string is shown as a tooltip 225 // when the mouse hovers over the building. set_production_result(const std::string & text)226 void set_production_result(const std::string& text) { 227 production_result_ = text; 228 } 229 230 InputQueue& inputqueue(DescriptionIndex, WareWorker) override; 231 232 bool init(EditorGameBase&) override; 233 void cleanup(EditorGameBase&) override; 234 void act(Game&, uint32_t data) override; 235 236 void remove_worker(Worker&) override; 237 int warp_worker(EditorGameBase&, const WorkerDescr& wd); 238 239 bool fetch_from_flag(Game&) override; 240 bool get_building_work(Game&, Worker&, bool success) override; 241 242 void set_economy(Economy*, WareWorker) override; 243 244 using InputQueues = std::vector<InputQueue*>; inputqueues()245 const InputQueues& inputqueues() const { 246 return input_queues_; 247 } 248 249 const std::vector<Worker*>& workers() const; 250 251 bool can_start_working() const; 252 253 /// sends a message to the player e.g. if the building's resource can't be found 254 void notify_player(Game& game, 255 uint8_t minutes, 256 FailNotificationType type = FailNotificationType::kDefault); 257 void unnotify_player(); 258 259 void set_default_anim(std::string); 260 261 const BuildingSettings* create_building_settings() const override; 262 263 protected: 264 void update_statistics_string(std::string* statistics) override; 265 266 void load_finish(EditorGameBase& egbase) override; 267 268 protected: 269 struct State { 270 const ProductionProgram* program; ///< currently running program 271 size_t ip; ///< instruction pointer 272 ProgramResult phase; ///< micro-step index (instruction dependent) 273 uint32_t flags; ///< pfXXX flags 274 275 /** 276 * Instruction-dependent additional data. 277 */ 278 /*@{*/ 279 ObjectPointer objvar; 280 Coords coord; 281 /*@}*/ 282 StateState283 State() 284 : program(nullptr), ip(0), phase(ProgramResult::kNone), flags(0), coord(Coords::null()) { 285 } 286 }; 287 288 Request& request_worker(DescriptionIndex); 289 static void 290 request_worker_callback(Game&, Request&, DescriptionIndex, Worker*, PlayerImmovable&); 291 292 /** 293 * Determine the next program to be run when the last program has finished. 294 * The default implementation starts program "work". 295 */ 296 virtual void find_and_start_next_program(Game&); 297 top_state()298 State& top_state() { 299 assert(stack_.size()); 300 return *stack_.rbegin(); 301 } get_state()302 State* get_state() { 303 return stack_.size() ? &*stack_.rbegin() : nullptr; 304 } 305 void program_act(Game&); 306 307 /// \param phase can be used to pass a value on to the next step in the 308 /// program. For example if one step is a mine command, it can calculate 309 /// how long it should take to mine, given the particular circumstances, 310 /// and pass the result to the following animation command, to set the 311 /// duration. 312 void program_step(Game&, uint32_t delay = 10, ProgramResult phase = ProgramResult::kNone); 313 314 void program_start(Game&, const std::string& program_name); 315 virtual void program_end(Game&, ProgramResult); 316 virtual void train_workers(Game&); 317 318 void format_statistics_string(); 319 void try_start_working(Game&); set_post_timer(int32_t const t)320 void set_post_timer(int32_t const t) { 321 post_timer_ = t; 322 } 323 324 protected: // TrainingSite must have access to this stuff 325 WorkingPosition* working_positions_; 326 327 int32_t fetchfromflag_; ///< Number of wares to fetch from flag 328 329 /// If a program has ended with the result Failed or Skipped, that program may not 330 /// start again until a certain time has passed. This is a map from program 331 /// name to game time. When a program ends with the result Failed or Skipped, its name 332 /// is added to this map, with the current game time. (When the program ends 333 /// with any other result, its name is removed from the map.) 334 using FailedSkippedPrograms = std::map<std::string, Time>; 335 FailedSkippedPrograms failed_skipped_programs_; 336 337 using Stack = std::vector<State>; 338 Stack stack_; ///< program stack 339 bool program_timer_; ///< execute next instruction based on pointer 340 int32_t program_time_; ///< timer time 341 int32_t post_timer_; ///< Time to schedule after ends 342 343 BillOfMaterials produced_wares_; 344 BillOfMaterials recruited_workers_; 345 InputQueues input_queues_; ///< input queues for all inputs 346 uint16_t last_stat_percent_; 347 // integer 0-10000000, to be divided by 10000 to get a percent, to avoid float (target range: 348 // 0-100) 349 uint32_t actual_percent_; // basically this is percent * 10 to avoid floats 350 uint32_t last_program_end_time; 351 bool is_stopped_; 352 std::string default_anim_; // normally "idle", "empty", if empty mine. 353 354 private: 355 enum class Trend { kUnchanged, kRising, kFalling }; 356 Trend trend_; 357 std::string statistics_string_on_changed_statistics_; 358 std::string production_result_; // hover tooltip text 359 360 int32_t main_worker_; 361 362 DISALLOW_COPY_AND_ASSIGN(ProductionSite); 363 }; 364 365 /** 366 * Describes, how many wares of a certain ware can be stored in a house. 367 * 368 * This class will be extended to support ordering of certain wares directly or 369 * releasing some wares out of a building 370 */ 371 struct Input { InputInput372 Input(const DescriptionIndex& Ware, uint8_t const Max) : ware_(Ware), max_(Max) { 373 } ~InputInput374 ~Input() { 375 } 376 wareInput377 DescriptionIndex ware() const { 378 return ware_; 379 } maxInput380 uint8_t max() const { 381 return max_; 382 } 383 384 private: 385 DescriptionIndex ware_; 386 uint8_t max_; 387 }; 388 389 /** 390 * Note to be published when a production site is out of resources 391 */ 392 // A note we're using to notify the AI 393 struct NoteProductionSiteOutOfResources { 394 CAN_BE_SENT_AS_NOTE(NoteId::ProductionSiteOutOfResources) 395 396 // The production site that is out of resources. 397 ProductionSite* ps; 398 399 // The player that owns the production site. 400 Player* player; 401 NoteProductionSiteOutOfResourcesNoteProductionSiteOutOfResources402 NoteProductionSiteOutOfResources(ProductionSite* const init_ps, Player* init_player) 403 : ps(init_ps), player(init_player) { 404 } 405 }; 406 407 } // namespace Widelands 408 409 #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_PRODUCTIONSITE_H 410