~widelands-dev/widelands/trunk

4677 by sigra
move more of the logic files into the logic directory
1
/*
10843 by The Widelands Bunnybot
Update copyright end year to 2024
2
 * Copyright (C) 2002-2024 by the Widelands Development Team
4677 by sigra
move more of the logic files into the logic directory
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
10152 by The Widelands Bunnybot
Add check for missing copyright headers (#5223)
15
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
4677 by sigra
move more of the logic files into the logic directory
16
 *
17
 */
18
7649.1.1 by fios at foramnagaidhlig
- Moved logic MapObjects and related classes into subdirectories.
19
#include "logic/map_objects/tribes/production_program.h"
4677 by sigra
move more of the logic files into the logic directory
20
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
21
#include <cassert>
7175.7.114 by fios at foramnagaidhlig
Added compatibility code for map immovables.
22
#include <memory>
7037 by Holger Rapp
Cleaned out helper.h.
23
6969.1.100 by Holger Rapp
Split io_fileread from io_filesystem.
24
#include "base/i18n.h"
7036 by Holger Rapp
Moved macros into base_macros.
25
#include "base/macros.h"
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
26
#include "base/math.h"
7707.1.11 by Holger Rapp
moved NEVER_HERE() into wexception.h and fixed codecheck.
27
#include "base/wexception.h"
6969.1.61 by Holger Rapp
refactored how warnings are defined and increased the warning verbosity for clang.
28
#include "config.h"
4677 by sigra
move more of the logic files into the logic directory
29
#include "economy/economy.h"
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
30
#include "economy/ferry_fleet.h"
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
31
#include "economy/flag.h"
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
32
#include "economy/input_queue.h"
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
33
#include "economy/ship_fleet.h"
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
34
#include "economy/wares_queue.h"
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
35
#include "io/filesystem/layered_filesystem.h"
6667.1.6 by Holger Rapp
Always need to include package names in widelands includes.
36
#include "logic/game.h"
37
#include "logic/game_data_error.h"
7649.1.1 by fios at foramnagaidhlig
- Moved logic MapObjects and related classes into subdirectories.
38
#include "logic/map_objects/checkstep.h"
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
39
#include "logic/map_objects/descriptions.h"
8494.1.1 by GunChleoc
Pulled out some libraries from liblogic. This makes the circular deoendencies more visible for future refactoring.
40
#include "logic/map_objects/findimmovable.h"
41
#include "logic/map_objects/findnode.h"
7649.1.1 by fios at foramnagaidhlig
- Moved logic MapObjects and related classes into subdirectories.
42
#include "logic/map_objects/tribes/productionsite.h"
43
#include "logic/map_objects/tribes/soldier.h"
44
#include "logic/map_objects/tribes/soldiercontrol.h"
45
#include "logic/map_objects/tribes/trainingsite.h"
46
#include "logic/map_objects/tribes/tribe_descr.h"
47
#include "logic/map_objects/tribes/worker_program.h"
48
#include "logic/map_objects/world/resource_description.h"
6667.1.6 by Holger Rapp
Always need to include package names in widelands includes.
49
#include "logic/mapregion.h"
50
#include "logic/player.h"
8307.2.1 by GunChleoc
Use notifications to remove dependencies from sound to logic and wui. Animation::trigger_sound is now called in Animation::blit. Moved widelands.h to wl_library logic_constants.
51
#include "sound/note_sound.h"
4677 by sigra
move more of the logic files into the logic directory
52
#include "sound/sound_handler.h"
4969.1.11 by Jari Hautio
Use HAVE_VARARRAY define to use varialbe lengh arrays if not compiling for MSVC. Whitespace cleanup.
53
4677 by sigra
move more of the logic files into the logic directory
54
namespace Widelands {
55
7037 by Holger Rapp
Cleaned out helper.h.
56
namespace {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
57
/// If the iterator contents match the string, increment the iterator. Returns whether it matched.
58
bool match_and_skip(const std::vector<std::string>& args,
59
                    std::vector<std::string>::const_iterator& it,
60
                    const std::string& matchme) {
61
	const bool result = (it != args.end()) && (*it == matchme);
62
	if (result) {
63
		++it;
64
	}
65
	return result;
66
}
67
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
68
/* RST
69
.. _productionsite_programs:
70
71
Productionsite Programs
72
=======================
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
73
Productionsites have :ref:`programs <map_object_programs>` that will be executed by the game
74
engine. Each productionsite must have a program named ``main``, which will be started automatically
75
when the productionsite is created in the game, and then repeated until the productionsite is
9471 by The Widelands Bunnybot
Program documentation (#4140)
76
destroyed.
77
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
78
Programs are defined as Lua tables. Each program must be declared as a subtable in the
79
productionsite's Lua table called ``programs`` and have a unique table key. The entries in a
80
program's subtable are the translatable ``descname`` and the table of ``actions`` to execute, like
81
this::
82
83
   programs = {
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
84
      main = {
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
85
         -- TRANSLATORS: Completed/Skipped/Did not start working because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
86
         descname = _("working"),
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
87
         actions = {
88
            <list of actions>
89
         }
90
      },
91
   },
92
93
The translations for ``descname`` can also be fetched by ``pgettext`` to disambiguate. We recommend
94
that you do this whenever workers are referenced, or if your tribes have multiple wares with the
95
same name::
96
97
   programs = {
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
98
      main = {
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
99
         -- TRANSLATORS: Completed/Skipped/Did not start recruiting soldier because ...
100
         descname = pgettext("atlanteans_building", "recruiting soldier"),
101
         actions = {
102
            <list of actions>
103
         }
104
      },
105
   },
106
107
A program can call another program, for example::
108
109
   programs = {
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
110
      main = {
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
111
         -- TRANSLATORS: Completed/Skipped/Did not start working because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
112
         descname = _("working"),
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
113
         actions = {
114
            "call=produce_ration",
115
            "call=produce_snack",
116
            "return=skipped"
117
         }
118
      },
119
      produce_ration = {
120
         -- TRANSLATORS: Completed/Skipped/Did not start preparing a ration because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
121
         descname = _("preparing a ration"),
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
122
         actions = {
123
            <list of actions>
124
         }
125
      },
126
      produce_snack = {
127
         -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
128
         descname = _("preparing a snack"),
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
129
         actions = {
130
            <list of actions>
131
         }
132
      },
133
   },
134
9420 by The Widelands Bunnybot
Document animations (#4059)
135
A program consists of a sequence of actions. An action is written as
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
136
``<type>=<parameters>``::
137
138
   produce_snack = {
139
      -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
140
      descname = _("preparing a snack"),
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
141
      actions = {
142
         "return=skipped unless economy needs snack",
9413 by The Widelands Bunnybot
Convert sleep program to new duration syntax (#4056)
143
         "sleep=duration:2s500ms",
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
144
         "consume=barbarians_bread fish,meat beer",
145
         "playsound=sound/barbarians/taverns/inn 100",
9413 by The Widelands Bunnybot
Convert sleep program to new duration syntax (#4056)
146
         "animate=working duration:22s",
147
         "sleep=duration:10s",
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
148
         "produce=snack"
149
      }
150
   },
151
152
153
.. highlight:: default
154
9420 by The Widelands Bunnybot
Document animations (#4059)
155
For general information about the format, see :ref:`map_object_programs_syntax`.
156
157
Available actions are:
158
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
159
- `animate`_
160
- `call`_
161
- `callworker`_
162
- `checksoldier`_
163
- `construct`_
164
- `consume`_
165
- `mine`_
166
- `playsound`_
167
- `recruit`_
168
- `produce`_
169
- `return`_
170
- `sleep`_
171
- `train`_
172
*/
173
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
174
ProductionProgram::ActReturn::Condition* create_economy_condition(
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
175
   const std::string& item, ProductionSiteDescr& descr, const Descriptions& descriptions) {
9461 by The Widelands Bunnybot
Tribes filtering (#3693)
176
	try {
9628 by The Widelands Bunnybot
Clear readability-redundant-control-flow (#4446)
177
		const std::pair<WareWorker, DescriptionIndex> wareworker =
178
		   descriptions.load_ware_or_worker(item);
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
179
		descr.set_infinite_production_useful(true);
9628 by The Widelands Bunnybot
Clear readability-redundant-control-flow (#4446)
180
		switch (wareworker.first) {
181
		case WareWorker::wwWARE: {
182
			descr.ware_demand_checks()->insert(wareworker.second);
183
			return new ProductionProgram::ActReturn::EconomyNeedsWare(wareworker.second);
184
		}
185
		case WareWorker::wwWORKER: {
186
			descr.worker_demand_checks()->insert(wareworker.second);
187
			return new ProductionProgram::ActReturn::EconomyNeedsWorker(wareworker.second);
188
		}
189
		}
190
		NEVER_HERE();
9461 by The Widelands Bunnybot
Tribes filtering (#3693)
191
	} catch (const GameDataError& e) {
192
		throw GameDataError("economy condition: %s", e.what());
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
193
	}
194
}
7037 by Holger Rapp
Cleaned out helper.h.
195
}  // namespace
5537 by Nasenbaer
Do not show "skipped work", etc. in statistics string of a building, as it is already shown in the hover message, it clutters the screen and hides the real statistics; add hover message that indicates that a mine is empty; fixed a string with boost::format to make it better translateable; added a TODO comment to a part, where boost::format should definitley be used; updated pot files
196
10191 by The Widelands Bunnybot
Fix misc clang-tidy checks in `logic` (#5255)
197
bool ProductionProgram::Action::get_building_work(Game& /* game */,
198
                                                  ProductionSite& /* site */,
199
                                                  Worker& /* worker */) const {
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
200
	return false;
201
}
202
10191 by The Widelands Bunnybot
Fix misc clang-tidy checks in `logic` (#5255)
203
void ProductionProgram::Action::building_work_failed(Game& /* game */,
204
                                                     ProductionSite& /* site */,
205
                                                     Worker& /* worker */) const {
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
206
}
207
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
208
ProductionProgram::Groups
209
ProductionProgram::parse_ware_type_groups(std::vector<std::string>::const_iterator begin,
210
                                          std::vector<std::string>::const_iterator end,
211
                                          const ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
212
                                          const Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
213
	ProductionProgram::Groups result;
214
215
	for (auto& it = begin; it != end; ++it) {
216
		const std::pair<std::string, std::string> names_to_amount =
217
		   read_key_value_pair(*it, ':', "1");
218
		const uint8_t amount = read_positive(names_to_amount.second);
219
		uint8_t max_amount = 0;
220
		std::set<std::pair<DescriptionIndex, WareWorker>> ware_worker_names;
221
		for (const std::string& item_name : split_string(names_to_amount.first, ",")) {
222
			// Try as ware
223
			WareWorker type = wwWARE;
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
224
			DescriptionIndex item_index = descriptions.ware_index(item_name);
225
			if (!descriptions.ware_exists(item_index)) {
226
				item_index = descriptions.worker_index(item_name);
227
				if (descriptions.worker_exists(item_index)) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
228
					// It is a worker
229
					type = wwWORKER;
230
				} else {
231
					throw GameDataError(
232
					   "Expected ware or worker type but found '%s'", item_name.c_str());
233
				}
234
			}
235
236
			// Sanity checks
237
			bool found = false;
238
			const BillOfMaterials& inputs =
239
			   (type == wwWARE) ? descr.input_wares() : descr.input_workers();
240
			for (const WareAmount& input : inputs) {
241
				if (input.first == item_index) {
242
					max_amount += input.second;
243
					found = true;
244
					break;
245
				}
246
			}
247
			if (!found) {
248
				throw GameDataError(
249
				   "%s was not declared in the building's 'inputs' table", item_name.c_str());
250
			}
251
252
			if (max_amount < amount) {
253
				throw GameDataError(
254
				   "Ware/worker count is %u but (total) input storage capacity of "
255
				   "the specified ware type(s) is only %u, so the ware/worker requirement can "
256
				   "never be fulfilled by the site",
257
				   static_cast<unsigned int>(amount), static_cast<unsigned int>(max_amount));
258
			}
259
			// Add item
260
			ware_worker_names.insert(std::make_pair(item_index, type));
261
		}
262
		// Add set
263
		result.push_back(std::make_pair(ware_worker_names, amount));
264
	}
265
	if (result.empty()) {
266
		throw GameDataError("No wares or workers found");
267
	}
268
	return result;
269
}
270
9373 by The Widelands Bunnybot
Add optional braces to wui (#3998)
271
BillOfMaterials ProductionProgram::parse_bill_of_materials(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
272
   const std::vector<std::string>& arguments, WareWorker ww, Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
273
	BillOfMaterials result;
274
	for (const std::string& argument : arguments) {
275
		const std::pair<std::string, std::string> produceme = read_key_value_pair(argument, ':', "1");
276
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
277
		const DescriptionIndex index = ww == WareWorker::wwWARE ?
9939 by The Widelands Bunnybot
GitHub action updates (#4735)
278
                                        descriptions.load_ware(produceme.first) :
279
                                        descriptions.load_worker(produceme.first);
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
280
281
		result.push_back(std::make_pair(index, read_positive(produceme.second)));
282
	}
283
	return result;
4721 by sigra
Move parsing of a ware type group (such as "fish,meat:2" out into a separate function.
284
}
285
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
286
ProductionProgram::Action::TrainingParameters::TrainingParameters(
287
   const std::vector<std::string>& arguments, const std::string& action_name) {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
288
	for (const std::string& argument : arguments) {
289
		const std::pair<std::string, std::string> item = read_key_value_pair(argument, ':');
290
		if (item.first == "soldier") {
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
291
			if (item.second == "health") {
292
				attribute = TrainingAttribute::kHealth;
293
			} else if (item.second == "attack") {
294
				attribute = TrainingAttribute::kAttack;
295
			} else if (item.second == "defense") {
296
				attribute = TrainingAttribute::kDefense;
297
			} else if (item.second == "evade") {
298
				attribute = TrainingAttribute::kEvade;
299
			} else {
300
				throw GameDataError(
301
				   "Expected health|attack|defense|evade after 'soldier' but found '%s'",
302
				   argument.c_str());
303
			}
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
304
		} else if (item.first == "level") {
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
305
			level = read_int(item.second, 0);
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
306
		} else {
307
			throw GameDataError(
308
			   "Unknown argument '%s'. Usage: %s=soldier:attack|defense|evade|health level:<number>",
309
			   item.first.c_str(), action_name.c_str());
310
		}
311
	}
312
}
313
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
314
/* RST
9471 by The Widelands Bunnybot
Program documentation (#4140)
315
.. _productionsite_programs_act_return:
316
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
317
return
318
------
9471 by The Widelands Bunnybot
Program documentation (#4140)
319
320
.. function:: return=completed|failed|skipped \[\<\condition\>\]
321
322
The ``return`` action determines how the program's result will update the productivity statistics
323
when any of its steps can't be completed:
324
325
* **completed**: Counts as a success for the productivity statistics.
326
* **failed**: Counts as a failure for the productivity statistics.
327
* **skipped**: Will be ignored by the productivity statistics.
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
328
329
.. note:: If the execution reaches the end of the program, the return value is implicitly set to
9471 by The Widelands Bunnybot
Program documentation (#4140)
330
   ``completed``.
331
332
If ``condition`` is specified, this will cause an immediate termination of the program if the
333
condition can't be satisfied. There are two types of conditions, using Boolean arithmetic:
334
335
   :when \<statement1\> \[and \<statement2\> ...\]: If any of these statements is false, the program
336
      will terminate immediately.
337
   :unless \<statement1\> \[or \<statement2\> ...\]: If none of these statements is true, the
338
      program will terminate immediately.
339
340
The individual statements can also be negated:
341
342
   :when not <statement1> and <statement2>: If ``<statement1>`` is true or ``<statement2>`` is
343
      false, the program will terminate immediately.
344
   :unless not <statement>: If ``<statement>`` is false, the program will terminate immediately.
345
346
The following statements are available:
347
348
   :site has <ware_types>|<worker_types>: Checks whether the building's input queues are filled
349
      with a certain amount of wares/workers. A ware or worker type may only appear once in the
350
      command. You can specify more than one ware. For example, ``site has fish,meat:2`` is true if
351
      the building has at least 1 fish or if the building has at least 2 meat.
352
   :workers need experience: This is true if a worker working at the building can currently gain
353
      some experience.
354
   :economy needs <ware_type>|<worker_type>: The result of this condition depends on
355
      whether the economy that this productionsite belongs to needs a ware or worker of the
356
      specified type. How this is determined is defined by the economy. A ware or worker type may
357
      only appear once in the command.
358
359
Examples for ``return=failed``:
360
361
.. code-block:: lua
362
363
   -- If the building has no 'ax_sharp' in its input queues, the program will fail immediately.
364
   return=failed unless site has ax_sharp
365
366
   -- If the building has less than 2 items of 'barbarians_bread' in its input queues, the program
367
   -- will fail immediately.
368
   return=failed unless site has barbarians_bread:2
369
370
   -- The building needs 1 item of 'bread_frisians', 'beer', 'smoked_fish' or 'smoked_meat' in its
371
   -- input queues. Otherwise, the program will fail immediately.
372
   return=failed unless site has bread_frisians,beer,smoked_fish,smoked_meat
373
374
   -- The building needs 1 item of 'fish' or 2 items of 'meat' in its input queues. Otherwise, the
375
   -- program will fail immediately.
376
   return=failed unless site has fish,meat:2
377
378
Examples for ``return=skipped``:
379
380
.. code-block:: lua
381
382
   -- If any subsequent step fails, don't cause a hit on the statistics.
383
   return=skipped
384
385
   -- Only run this program if the economy needs an 'ax_sharp'.
386
   return=skipped unless economy needs ax_sharp
387
388
   -- Only run this program if the economy needs a 'beer' or if any of the workers working at the
389
   -- building can gain more experience.
390
   return=skipped unless economy needs beer or workers need experience
391
392
   -- Only run this program if the economy needs at least one of the listed wares: 'clay', 'fish' or
393
   -- 'coal'.
394
   return=skipped unless economy needs clay or economy needs fish or economy needs coal
395
396
   -- Only run this program if the economy needs at least one of the listed wares: 'iron' or 'gold'.
397
   -- If the economy has sufficient 'coal', run anyway even if none of these two wares are needed.
398
   return=skipped unless economy needs iron or economy needs gold or not economy needs coal
399
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
400
   -- If the building has no 'fur_garment_old' in its input queues, skip running this program.
9471 by The Widelands Bunnybot
Program documentation (#4140)
401
   return=skipped unless site has fur_garment_old
402
403
   -- If the building has 'wheat' in its input queue and if the economy needs the ware
404
   -- 'flour' but does not need the ware 'cornmeal', skip running this program so we can run another
405
   -- program for producing 'flour' rather than 'cornmeal'.
406
   return=skipped when site has wheat and economy needs flour and not economy needs cornmeal
407
408
   -- If the building has at least 2 items of 'fish' in its input queues and if the economy needs
409
   -- any 'smoked_fish', skip running this program because we will want to produce some
410
   -- 'smoked_fish' instead of whatever this program produces.
411
   return=skipped when site has fish:2 and economy needs smoked_fish
412
413
   -- If the building has at least one item of 'fruit' or 'bread_frisians' and at least one item of
414
   -- 'smoked_fish' or 'smoked_meat', skip running this program. We want to do something more useful
415
   -- with these wares with another program.
416
   return=skipped when site has fruit,bread_frisians and site has smoked_fish,smoked_meat
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
417
*/
4677 by sigra
move more of the logic files into the logic directory
418
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
419
ProductionProgram::ActReturn::Negation::Negation(const std::vector<std::string>& arguments,
420
                                                 std::vector<std::string>::const_iterator& begin,
421
                                                 std::vector<std::string>::const_iterator& end,
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
422
                                                 ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
423
                                                 const Descriptions& descriptions)
424
   : operand(create_condition(arguments, begin, end, descr, descriptions)) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
425
}
426
4677 by sigra
move more of the logic files into the logic directory
427
ProductionProgram::ActReturn::Negation::~Negation() {
428
	delete operand;
429
}
8048 by GunChleoc
Ran clang-format.
430
bool ProductionProgram::ActReturn::Negation::evaluate(const ProductionSite& ps) const {
7119.4.10 by fios at foramnagaidhlig
Cleaned up logic operators in logic
431
	return !operand->evaluate(ps);
4677 by sigra
move more of the logic files into the logic directory
432
}
7150.5.9 by fios at foramnagaidhlig
Fixed the bug from the last commit
433
7185.2.1 by fios at foramnagaidhlig
ProductionProgram::ActReturn::Negation dummies now return empty string instead of throwing an exception.
434
// Just a dummy to satisfy the superclass interface. Returns an empty string.
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
435
std::string ProductionProgram::ActReturn::Negation::description(const Descriptions& t) const {
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
436
	return operand->description_negation(t);
7150.5.9 by fios at foramnagaidhlig
Fixed the bug from the last commit
437
}
438
7185.2.1 by fios at foramnagaidhlig
ProductionProgram::ActReturn::Negation dummies now return empty string instead of throwing an exception.
439
// Just a dummy to satisfy the superclass interface. Returns an empty string.
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
440
std::string
441
ProductionProgram::ActReturn::Negation::description_negation(const Descriptions& t) const {
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
442
	return operand->description(t);
4716 by sigra
Show in the statistics string why a building is not working. This is intended to reduce the number of complaints like "my sawmill is not working even though it has trunks".
443
}
4677 by sigra
move more of the logic files into the logic directory
444
8048 by GunChleoc
Ran clang-format.
445
bool ProductionProgram::ActReturn::EconomyNeedsWare::evaluate(const ProductionSite& ps) const {
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
446
	return ps.infinite_production() || ps.get_economy(wwWARE)->needs_ware_or_worker(ware_type);
4677 by sigra
move more of the logic files into the logic directory
447
}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
448
std::string ProductionProgram::ActReturn::EconomyNeedsWare::description(
449
   const Descriptions& descriptions) const {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
450
	std::string result = format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
451
	   /** TRANSLATORS: e.g. Completed/Skipped/Did not start ... because the economy needs the ware
452
	    * '%s' */
453
	   _("the economy needs the ware ‘%s’"), descriptions.get_ware_descr(ware_type)->descname());
7225.1.2 by fios at foramnagaidhlig
Removed all direct usaged of c_str() in conjunction with boost::format
454
	return result;
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
455
}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
456
std::string ProductionProgram::ActReturn::EconomyNeedsWare::description_negation(
457
   const Descriptions& descriptions) const {
9092 by GunChleoc
Fixed codecheck.
458
	/** TRANSLATORS: e.g. Completed/Skipped/Did not start ... because the economy doesn't need the
459
	 * ware '%s' */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
460
	std::string result = format(_("the economy doesn’t need the ware ‘%s’"),
461
	                            descriptions.get_ware_descr(ware_type)->descname());
7225.1.2 by fios at foramnagaidhlig
Removed all direct usaged of c_str() in conjunction with boost::format
462
	return result;
4716 by sigra
Show in the statistics string why a building is not working. This is intended to reduce the number of complaints like "my sawmill is not working even though it has trunks".
463
}
4677 by sigra
move more of the logic files into the logic directory
464
8048 by GunChleoc
Ran clang-format.
465
bool ProductionProgram::ActReturn::EconomyNeedsWorker::evaluate(const ProductionSite& ps) const {
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
466
	return ps.infinite_production() || ps.get_economy(wwWORKER)->needs_ware_or_worker(worker_type);
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
467
}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
468
std::string ProductionProgram::ActReturn::EconomyNeedsWorker::description(
469
   const Descriptions& descriptions) const {
8048 by GunChleoc
Ran clang-format.
470
	/** TRANSLATORS: e.g. Completed/Skipped/Did not start ... because the economy needs the worker
9092 by GunChleoc
Fixed codecheck.
471
	 * '%s' */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
472
	std::string result = format(_("the economy needs the worker ‘%s’"),
473
	                            descriptions.get_worker_descr(worker_type)->descname());
7225.1.2 by fios at foramnagaidhlig
Removed all direct usaged of c_str() in conjunction with boost::format
474
	return result;
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
475
}
476
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
477
std::string ProductionProgram::ActReturn::EconomyNeedsWorker::description_negation(
478
   const Descriptions& descriptions) const {
9092 by GunChleoc
Fixed codecheck.
479
	/** TRANSLATORS: e.g. Completed/Skipped/Did not start ... */
480
	/** TRANSLATORS:      ... because the economy doesn’t need the worker '%s' */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
481
	std::string result = format(_("the economy doesn’t need the worker ‘%s’"),
482
	                            descriptions.get_worker_descr(worker_type)->descname());
7225.1.2 by fios at foramnagaidhlig
Removed all direct usaged of c_str() in conjunction with boost::format
483
	return result;
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
484
}
485
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
486
ProductionProgram::ActReturn::SiteHas::SiteHas(std::vector<std::string>::const_iterator begin,
487
                                               std::vector<std::string>::const_iterator end,
8048 by GunChleoc
Ran clang-format.
488
                                               const ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
489
                                               const Descriptions& descriptions) {
4722 by sigra
* When parsing a consume group, check that the count is not so large that the group can not be fulfilled by the site. For example if a site has "[inputs]" "smoked_fish=6", "smoked_meat=6" and a program has a consume command with the group "smoked_fish,smoked_meat:13" it will give an error message (previously it was just accepted silently).
490
	try {
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
491
		group = parse_ware_type_groups(begin, end, descr, descriptions).front();
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
492
	} catch (const GameDataError& e) {
493
		throw GameDataError("Expected <ware or worker>[,<ware or worker>[,...]][:<amount>] after "
494
		                    "'site has' but got %s",
495
		                    e.what());
4722 by sigra
* When parsing a consume group, check that the count is not so large that the group can not be fulfilled by the site. For example if a site has "[inputs]" "smoked_fish=6", "smoked_meat=6" and a program has a consume command with the group "smoked_fish,smoked_meat:13" it will give an error message (previously it was just accepted silently).
496
	}
497
}
8048 by GunChleoc
Ran clang-format.
498
bool ProductionProgram::ActReturn::SiteHas::evaluate(const ProductionSite& ps) const {
4722 by sigra
* When parsing a consume group, check that the count is not so large that the group can not be fulfilled by the site. For example if a site has "[inputs]" "smoked_fish=6", "smoked_meat=6" and a program has a consume command with the group "smoked_fish,smoked_meat:13" it will give an error message (previously it was just accepted silently).
499
	uint8_t count = group.second;
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
500
	for (InputQueue* ip_queue : ps.inputqueues()) {
501
		for (const auto& input_type : group.first) {
8265 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1658616-inputqueue-build19.
502
			if (input_type.first == ip_queue->get_index() &&
503
			    input_type.second == ip_queue->get_type()) {
7175.17.13 by GunChleoc
clang-format.
504
				uint8_t const filled = ip_queue->get_filled();
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
505
				if (count <= filled) {
7175.17.13 by GunChleoc
clang-format.
506
					return true;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
507
				}
7175.17.13 by GunChleoc
clang-format.
508
				count -= filled;
509
				break;
510
			}
4722 by sigra
* When parsing a consume group, check that the count is not so large that the group can not be fulfilled by the site. For example if a site has "[inputs]" "smoked_fish=6", "smoked_meat=6" and a program has a consume command with the group "smoked_fish,smoked_meat:13" it will give an error message (previously it was just accepted silently).
511
		}
7125.2.8 by fios at foramnagaidhlig
Don't need the typedefs for the pairs.
512
	}
4722 by sigra
* When parsing a consume group, check that the count is not so large that the group can not be fulfilled by the site. For example if a site has "[inputs]" "smoked_fish=6", "smoked_meat=6" and a program has a consume command with the group "smoked_fish,smoked_meat:13" it will give an error message (previously it was just accepted silently).
513
	return false;
514
}
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
515
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
516
std::string
517
ProductionProgram::ActReturn::SiteHas::description(const Descriptions& descriptions) const {
8048 by GunChleoc
Ran clang-format.
518
	std::vector<std::string> condition_list;
7175.17.3 by Notabilis
Merge with trunk.
519
	for (const auto& entry : group.first) {
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
520
		condition_list.push_back(entry.second == wwWARE ?
9939 by The Widelands Bunnybot
GitHub action updates (#4735)
521
                                  descriptions.get_ware_descr(entry.first)->descname() :
522
                                  descriptions.get_worker_descr(entry.first)->descname());
8048 by GunChleoc
Ran clang-format.
523
	}
524
	std::string condition = i18n::localize_list(condition_list, i18n::ConcatenateWith::AND);
525
	if (1 < group.second) {
526
		condition =
8497 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/codecheck_translations:
527
		   /** TRANSLATORS: This is an item in a list of wares, e.g. "3x water": */
528
		   /** TRANSLATORS:    %1$i = "3" */
529
		   /** TRANSLATORS:    %2$s = "water" */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
530
		   format(_("%1$ix %2$s"), static_cast<unsigned int>(group.second), condition);
8048 by GunChleoc
Ran clang-format.
531
	}
532
533
	std::string result =
8497 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/codecheck_translations:
534
	   /** TRANSLATORS: %s is a list of wares*/
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
535
	   format(_("the building has the following wares: %s"), condition);
8048 by GunChleoc
Ran clang-format.
536
	return result;
537
}
538
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
539
std::string ProductionProgram::ActReturn::SiteHas::description_negation(
540
   const Descriptions& descriptions) const {
8048 by GunChleoc
Ran clang-format.
541
	std::vector<std::string> condition_list;
7175.17.3 by Notabilis
Merge with trunk.
542
	for (const auto& entry : group.first) {
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
543
		condition_list.push_back(entry.second == wwWARE ?
9939 by The Widelands Bunnybot
GitHub action updates (#4735)
544
                                  descriptions.get_ware_descr(entry.first)->descname() :
545
                                  descriptions.get_worker_descr(entry.first)->descname());
8048 by GunChleoc
Ran clang-format.
546
	}
547
	std::string condition = i18n::localize_list(condition_list, i18n::ConcatenateWith::AND);
548
	if (1 < group.second) {
549
		condition =
8497 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/codecheck_translations:
550
		   /** TRANSLATORS: This is an item in a list of wares, e.g. "3x water": */
551
		   /** TRANSLATORS:    %1$i = "3" */
552
		   /** TRANSLATORS:    %2$s = "water" */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
553
		   format(_("%1$ix %2$s"), static_cast<unsigned int>(group.second), condition);
8048 by GunChleoc
Ran clang-format.
554
	}
555
8483.1.2 by GunChleoc
Fixed codecheck.
556
	std::string result =
8497 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/codecheck_translations:
557
	   /** TRANSLATORS: %s is a list of wares*/
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
558
	   format(_("the building doesn’t have the following wares: %s"), condition);
8048 by GunChleoc
Ran clang-format.
559
	return result;
560
}
561
562
bool ProductionProgram::ActReturn::WorkersNeedExperience::evaluate(const ProductionSite& ps) const {
10050 by The Widelands Bunnybot
Intelligent worker reordering (#5099)
563
	const std::vector<ProductionSite::WorkingPosition>& wp = ps.working_positions_;
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
564
	for (uint32_t i = ps.descr().nr_working_positions(); i != 0u;) {
10050 by The Widelands Bunnybot
Intelligent worker reordering (#5099)
565
		if (wp.at(--i).worker.get(ps.get_owner()->egbase())->needs_experience()) {
4677 by sigra
move more of the logic files into the logic directory
566
			return true;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
567
		}
568
	}
4677 by sigra
move more of the logic files into the logic directory
569
	return false;
570
}
10191 by The Widelands Bunnybot
Fix misc clang-tidy checks in `logic` (#5255)
571
std::string ProductionProgram::ActReturn::WorkersNeedExperience::description(
572
   const Descriptions& /* descriptions */) const {
7150.5.10 by fios at foramnagaidhlig
Changed the wording of some strings so they can work together with the tribes' conf files
573
	/** TRANSLATORS: 'Completed/Skipped/Did not start ... because a worker needs experience'. */
574
	return _("a worker needs experience");
4716 by sigra
Show in the statistics string why a building is not working. This is intended to reduce the number of complaints like "my sawmill is not working even though it has trunks".
575
}
4677 by sigra
move more of the logic files into the logic directory
576
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
577
std::string ProductionProgram::ActReturn::WorkersNeedExperience::description_negation(
10191 by The Widelands Bunnybot
Fix misc clang-tidy checks in `logic` (#5255)
578
   const Descriptions& /* descriptions */) const {
7150.5.10 by fios at foramnagaidhlig
Changed the wording of some strings so they can work together with the tribes' conf files
579
	/** TRANSLATORS: 'Completed/Skipped/Did not start ... because the workers need no experience'. */
580
	return _("the workers need no experience");
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
581
}
582
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
583
bool ProductionProgram::ActReturn::FleetNeeds::evaluate(const ProductionSite& ps) const {
584
	if (type_ == Type::kShip) {
585
		for (ShipFleetYardInterface* interface : ps.get_ship_fleet_interfaces()) {
586
			if (interface->get_fleet()->lacks_ship() || ps.infinite_production()) {
587
				BaseImmovable* immo = interface->get_position().field->get_immovable();
588
				if (immo == nullptr || immo->get_size() == BaseImmovable::Size::NONE) {
589
					return true;
590
				}
591
			}
592
		}
593
	} else {
594
		for (FerryFleetYardInterface* interface : ps.get_ferry_fleet_interfaces()) {
595
			if (interface->get_fleet()->lacks_ferry() || ps.infinite_production()) {
596
				BaseImmovable* immo = interface->get_position().field->get_immovable();
597
				if (immo == nullptr || immo->get_size() == BaseImmovable::Size::NONE) {
598
					return true;
599
				}
600
			}
601
		}
602
	}
603
604
	return false;
605
}
606
std::string ProductionProgram::ActReturn::FleetNeeds::description(
607
   const Descriptions& /* descriptions */) const {
608
	/** TRANSLATORS: 'Completed/Skipped/Did not start ... because the fleet needs a ship/ferry'. */
609
	return type_ == Type::kShip ? _("the fleet needs a ship") : _("the fleet needs a ferry");
610
}
611
612
std::string ProductionProgram::ActReturn::FleetNeeds::description_negation(
613
   const Descriptions& /* descriptions */) const {
614
	/** TRANSLATORS: 'Completed/Skipped/Did not start ... because the fleet needs no ships/ferries'.
615
	 */
616
	return type_ == Type::kShip ? _("the fleet needs no ships") : _("the fleet needs no ferries");
617
}
618
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
619
ProductionProgram::ActReturn::Condition*
620
ProductionProgram::ActReturn::create_condition(const std::vector<std::string>& arguments,
621
                                               std::vector<std::string>::const_iterator& begin,
622
                                               std::vector<std::string>::const_iterator& end,
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
623
                                               ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
624
                                               const Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
625
	if (begin == end) {
626
		throw GameDataError("Expected a condition after '%s'", (begin - 1)->c_str());
627
	}
4677 by sigra
move more of the logic files into the logic directory
628
	try {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
629
		if (match_and_skip(arguments, begin, "not")) {
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
630
			return new ActReturn::Negation(arguments, begin, end, descr, descriptions);
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
631
		}
632
		if (match_and_skip(arguments, begin, "economy")) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
633
			if (!match_and_skip(arguments, begin, "needs")) {
634
				throw GameDataError("Expected 'needs' after 'economy' but found '%s'", begin->c_str());
635
			}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
636
			return create_economy_condition(*begin, descr, descriptions);
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
637
		}
638
		if (match_and_skip(arguments, begin, "site")) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
639
			if (!match_and_skip(arguments, begin, "has")) {
640
				throw GameDataError("Expected 'has' after 'site' but found '%s'", begin->c_str());
641
			}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
642
			return new ProductionProgram::ActReturn::SiteHas(begin, end, descr, descriptions);
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
643
		}
644
		if (match_and_skip(arguments, begin, "workers")) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
645
			if (!match_and_skip(arguments, begin, "need")) {
646
				throw GameDataError(
647
				   "Expected 'need experience' after 'workers' but found '%s'", begin->c_str());
648
			}
649
			if (!match_and_skip(arguments, begin, "experience")) {
650
				throw GameDataError(
651
				   "Expected 'experience' after 'workers need' but found '%s'", begin->c_str());
652
			}
653
			return new ProductionProgram::ActReturn::WorkersNeedExperience();
654
		}
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
655
		if (match_and_skip(arguments, begin, "fleet")) {
656
			if (!match_and_skip(arguments, begin, "needs")) {
657
				throw GameDataError(
658
				   "Expected 'needs ship|ferry' after 'fleet' but found '%s'", begin->c_str());
659
			}
660
			descr.set_infinite_production_useful(true);
661
			if (match_and_skip(arguments, begin, "ship")) {
662
				descr.has_ship_fleet_check_ = true;
663
				return new ProductionProgram::ActReturn::FleetNeeds(
664
				   ProductionProgram::ActReturn::FleetNeeds::Type::kShip);
665
			}
666
			if (match_and_skip(arguments, begin, "ferry")) {
667
				descr.has_ferry_fleet_check_ = true;
668
				return new ProductionProgram::ActReturn::FleetNeeds(
669
				   ProductionProgram::ActReturn::FleetNeeds::Type::kFerry);
670
			}
671
			throw GameDataError("Expected 'ship' or 'ferry' after 'fleet needs' but found '%s'",
672
			                    begin == end ? "" : begin->c_str());
673
		}
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
674
		throw GameDataError("Expected not|economy|site|workers after '%s' but found '%s'",
675
		                    (begin - 1)->c_str(), begin->c_str());
8048 by GunChleoc
Ran clang-format.
676
	} catch (const WException& e) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
677
		throw GameDataError("Invalid condition. %s", e.what());
4677 by sigra
move more of the logic files into the logic directory
678
	}
679
}
680
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
681
ProductionProgram::ActReturn::ActReturn(const std::vector<std::string>& arguments,
10464 by The Widelands Bunnybot
Allow letting individual productionsites produce indefinitely (#4961)
682
                                        ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
683
                                        const Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
684
	if (arguments.empty()) {
9279 by The Widelands Bunnybot
Removed `return=no_stats` from productionsite programs (#3865)
685
		throw GameDataError("Usage: return=failed|completed|skipped [when|unless <conditions>]");
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
686
	}
687
	auto begin = arguments.begin();
688
689
	if (match_and_skip(arguments, begin, "failed")) {
690
		result_ = ProgramResult::kFailed;
691
	} else if (match_and_skip(arguments, begin, "completed")) {
692
		result_ = ProgramResult::kCompleted;
693
	} else if (match_and_skip(arguments, begin, "skipped")) {
694
		result_ = ProgramResult::kSkipped;
695
	} else {
9279 by The Widelands Bunnybot
Removed `return=no_stats` from productionsite programs (#3865)
696
		throw GameDataError("Usage: return=failed|completed|skipped [when|unless <conditions>]");
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
697
	}
698
699
	// Parse all arguments starting from the given iterator into our 'conditions_', splitting
700
	// individual conditions by the given 'separator'
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
701
	auto parse_conditions = [this, &descr, &descriptions](
702
	                           const std::vector<std::string>& args,
703
	                           std::vector<std::string>::const_iterator it,
704
	                           const std::string& separator) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
705
		while (it != args.end()) {
706
			auto end = it + 1;
707
			while (end != args.end() && *end != separator) {
708
				++end;
709
			}
710
			if (it == end) {
8048 by GunChleoc
Ran clang-format.
711
				throw GameDataError(
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
712
				   "Expected: [%s] <condition> after '%s'", separator.c_str(), (it - 1)->c_str());
713
			}
714
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
715
			conditions_.push_back(create_condition(args, it, end, descr, descriptions));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
716
			match_and_skip(args, end, separator);
717
			it = end;
718
		}
719
	};
720
721
	is_when_ = true;
722
	if (begin != arguments.end()) {
723
		if (match_and_skip(arguments, begin, "when")) {
724
			parse_conditions(arguments, begin, "and");
725
		} else if (match_and_skip(arguments, begin, "unless")) {
726
			is_when_ = false;
727
			parse_conditions(arguments, begin, "or");
728
		} else {
729
			throw GameDataError("Expected when|unless but found '%s'", begin->c_str());
730
		}
4677 by sigra
move more of the logic files into the logic directory
731
	}
732
}
733
734
ProductionProgram::ActReturn::~ActReturn() {
8048 by GunChleoc
Ran clang-format.
735
	for (Condition* condition : conditions_) {
7125.2.8 by fios at foramnagaidhlig
Don't need the typedefs for the pairs.
736
		delete condition;
737
	}
4677 by sigra
move more of the logic files into the logic directory
738
}
739
8048 by GunChleoc
Ran clang-format.
740
void ProductionProgram::ActReturn::execute(Game& game, ProductionSite& ps) const {
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
741
	if (!conditions_.empty()) {
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
742
		std::vector<std::string> condition_list;
8048 by GunChleoc
Ran clang-format.
743
		if (is_when_) {  //  'when a and b and ...' (all conditions must be true)
744
			for (const Condition* condition : conditions_) {
745
				if (!condition->evaluate(ps)) {   //  A condition is false,
746
					return ps.program_step(game);  //  continue program.
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
747
				}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
748
				condition_list.push_back(condition->description(game.descriptions()));
4920 by sigra
* Revert revision 4999, that added commands to schedule message expirations when messages are loaded. It is useless because the command queue has not been loaded yet (and will be cleared before being loaded). There was already code to schedule message expirations right after loading the command queue in Game_Loader::load_game. Add a comment about this where the messages are loaded. Revision 4999 did not fix the bug that it was supposed to fix. I have tried to reproduce it without success (the bug report does not provide a way to reproduce it). Messages seem to expire as expected whether they are added with Player::add_message, Player::add_message_with_timeout or loaded from a savegame.
749
			}
8048 by GunChleoc
Ran clang-format.
750
		} else {  //  "unless a or b or ..." (all conditions must be false)
751
			for (const Condition* condition : conditions_) {
752
				if (condition->evaluate(ps)) {    //  A condition is true,
753
					return ps.program_step(game);  //  continue program.
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
754
				}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
755
				condition_list.push_back(condition->description_negation(game.descriptions()));
4920 by sigra
* Revert revision 4999, that added commands to schedule message expirations when messages are loaded. It is useless because the command queue has not been loaded yet (and will be cleared before being loaded). There was already code to schedule message expirations right after loading the command queue in Game_Loader::load_game. Add a comment about this where the messages are loaded. Revision 4999 did not fix the bug that it was supposed to fix. I have tried to reproduce it without success (the bug report does not provide a way to reproduce it). Messages seem to expire as expected whether they are added with Player::add_message, Player::add_message_with_timeout or loaded from a savegame.
756
			}
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
757
		}
8048 by GunChleoc
Ran clang-format.
758
		std::string condition_string =
759
		   i18n::localize_list(condition_list, i18n::ConcatenateWith::AND);
7150.5.8 by fios at foramnagaidhlig
Added new function "description_negation" to struct Condition for natural language stuff, but test_economy doesn't like:
760
8385.3.9 by GunChleoc
Removed empty string initializations.
761
		std::string result_string;
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
762
		switch (result_) {
763
		case ProgramResult::kFailed: {
9092 by GunChleoc
Fixed codecheck.
764
			/** TRANSLATORS: "Did not start working because the economy needs the ware '%s'" */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
765
			result_string = format(_("Did not start %1$s because %2$s"),
766
			                       ps.top_state().program->descname(), condition_string);
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
767
		} break;
768
		case ProgramResult::kCompleted: {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
769
			result_string = format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
770
			   /** TRANSLATORS: "Completed working because the economy needs the ware '%s'" */
771
			   _("Completed %1$s because %2$s"), ps.top_state().program->descname(), condition_string);
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
772
		} break;
773
		case ProgramResult::kSkipped: {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
774
			result_string = format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
775
			   /** TRANSLATORS: "Skipped working because the economy needs the ware '%s'" */
776
			   _("Skipped %1$s because %2$s"), ps.top_state().program->descname(), condition_string);
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
777
		} break;
778
		case ProgramResult::kNone: {
9038.1.5 by GunChleoc
Cleanup
779
			// TODO(GunChleoc): Same as skipped - is this on purpose?
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
780
			result_string = format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
781
			   _("Skipped %1$s because %2$s"), ps.top_state().program->descname(), condition_string);
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
782
		}
783
		}
9090 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1489295-mine-is-exhausted:
784
		if (ps.production_result() != ps.descr().out_of_resource_heading() ||
785
		    ps.descr().out_of_resource_heading().empty()) {
9089.1.4 by hessenfarmer
suppressed also the "produced ..." and the "did not start cause the economy doesn't need..." message if a valid out of ressource message is set.
786
			ps.set_production_result(result_string);
787
		}
4677 by sigra
move more of the logic files into the logic directory
788
	}
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
789
	return ps.program_end(game, result_);
4677 by sigra
move more of the logic files into the logic directory
790
}
791
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
792
/* RST
793
call
794
----
9471 by The Widelands Bunnybot
Program documentation (#4140)
795
.. function:: call=\<program_name\> \[on failure|completion|skip fail|complete|skip|repeat\]
796
797
   :arg string program_name: The name of a :ref:`program <productionsite_programs>`
798
      defined in this productionsite.
799
800
   :arg string on: Defines what to do if the program fails, completes or skips.
801
802
      * ``complete``: The failure is ignored, and the program returns as successful.
803
      * ``fail``: The command fails, with the same effect as executing the :ref:`return program
804
        <productionsite_programs_act_return>` with ``return=failed``.
805
      * ``repeat``: The command is repeated.
806
      * ``skip``: The failure is ignored, and the program is continued. This is the default setting
807
        if ``on`` is ommitted.
808
809
Calls another program of the same productionsite. Example:
810
811
.. code-block:: lua
812
813
      -- Productionsite program that will mine marble 1 out of 3 times
814
      programs = {
815
         main = {
816
            -- TRANSLATORS: Completed/Skipped/Did not start working because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
817
            descname = _("working"),
9471 by The Widelands Bunnybot
Program documentation (#4140)
818
            actions = {
819
               "call=mine_granite on failure fail",
820
               "call=mine_granite on failure fail",
821
               "call=mine_marble on failure fail",
822
            }
823
         },
824
         mine_granite = {
825
            -- TRANSLATORS: Completed/Skipped/Did not start quarrying granite because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
826
            descname = _("quarrying granite"),
9471 by The Widelands Bunnybot
Program documentation (#4140)
827
            actions = {
828
               "callworker=cut_granite",
829
               "sleep=duration:17s500ms"
830
            }
831
         },
832
         mine_marble = {
833
            -- TRANSLATORS: Completed/Skipped/Did not start quarrying marble because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
834
            descname = _("quarrying marble"),
9471 by The Widelands Bunnybot
Program documentation (#4140)
835
            actions = {
836
               "callworker=cut_marble",
837
               "sleep=duration:17s500ms"
838
            }
839
         },
840
      },
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
841
*/
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
842
ProductionProgram::ActCall::ActCall(const std::vector<std::string>& arguments) {
9631 by The Widelands Bunnybot
Clear readability-container-size-empty (#4445)
843
	if (arguments.empty() || arguments.size() > 4) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
844
		throw GameDataError(
845
		   "Usage: call=<program name> [on failure|completion|skip fail|complete|skip|repeat]");
846
	}
847
4753 by sigra
In productionsite programs: Generalize failure handling method to result handling method. Depending on the result of the called program, the calling program can now return failed, completed or skipped. It can also chose to continue execution or repeat the call.
848
	//  Initialize with default handling methods.
9042 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1823612-llvm8-build-errors:
849
	handling_methods_[program_result_index(ProgramResult::kFailed)] =
850
	   ProgramResultHandlingMethod::kContinue;
851
	handling_methods_[program_result_index(ProgramResult::kCompleted)] =
852
	   ProgramResultHandlingMethod::kContinue;
853
	handling_methods_[program_result_index(ProgramResult::kSkipped)] =
854
	   ProgramResultHandlingMethod::kContinue;
4753 by sigra
In productionsite programs: Generalize failure handling method to result handling method. Depending on the result of the called program, the calling program can now return failed, completed or skipped. It can also chose to continue execution or repeat the call.
855
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
856
	// Fetch program to call
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
857
	program_name_ = arguments.front();
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
858
859
	//  Override with specified handling methods.
860
	if (arguments.size() > 1) {
861
		if (arguments.at(1) != "on") {
862
			throw GameDataError("Expected 'on' keyword in second position");
863
		}
864
865
		ProgramResult result_to_set_method_for;
866
		if (arguments.at(2) == "failure") {
867
			if (handling_methods_[program_result_index(ProgramResult::kFailed)] !=
868
			    ProgramResultHandlingMethod::kContinue) {
869
				throw GameDataError("%s handling method already defined", "failure");
870
			}
871
			result_to_set_method_for = ProgramResult::kFailed;
872
		} else if (arguments.at(2) == "completion") {
873
			if (handling_methods_[program_result_index(ProgramResult::kCompleted)] !=
874
			    ProgramResultHandlingMethod::kContinue) {
875
				throw GameDataError("%s handling method already defined", "completion");
876
			}
877
			result_to_set_method_for = ProgramResult::kCompleted;
878
		} else if (arguments.at(2) == "skip") {
879
			if (handling_methods_[program_result_index(ProgramResult::kSkipped)] !=
880
			    ProgramResultHandlingMethod::kContinue) {
881
				throw GameDataError("%s handling method already defined", "skip");
882
			}
883
			result_to_set_method_for = ProgramResult::kSkipped;
884
		} else {
885
			throw GameDataError(
886
			   "Expected failure|completion|skip after 'on' but found '%s'", arguments.at(2).c_str());
887
		}
888
889
		ProgramResultHandlingMethod handling_method;
890
		if (arguments.at(3) == "fail") {
891
			handling_method = ProgramResultHandlingMethod::kFail;
892
		} else if (arguments.at(3) == "complete") {
893
			handling_method = ProgramResultHandlingMethod::kComplete;
894
		} else if (arguments.at(3) == "skip") {
895
			handling_method = ProgramResultHandlingMethod::kSkip;
896
		} else if (arguments.at(3) == "repeat") {
897
			handling_method = ProgramResultHandlingMethod::kRepeat;
898
		} else {
899
			throw GameDataError("Expected fail|complete|skip|repeat in final position but found '%s'",
900
			                    arguments.at(3).c_str());
901
		}
902
		handling_methods_[program_result_index(result_to_set_method_for)] = handling_method;
4677 by sigra
move more of the logic files into the logic directory
903
	}
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
904
905
	assert(!program_name_.empty());
4677 by sigra
move more of the logic files into the logic directory
906
}
907
8048 by GunChleoc
Ran clang-format.
908
void ProductionProgram::ActCall::execute(Game& game, ProductionSite& ps) const {
9038.1.10 by GunChleoc
Production program phases are now ProductionResults. This uncovered some suble bugs where ActSleep and ActAnimate would change the phase.
909
	ProgramResult const program_result = ps.top_state().phase;
4753 by sigra
In productionsite programs: Generalize failure handling method to result handling method. Depending on the result of the called program, the calling program can now return failed, completed or skipped. It can also chose to continue execution or repeat the call.
910
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
911
	if (program_result == ProgramResult::kNone) {  //  The program has not yet been called.
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
912
		return ps.program_start(game, program_name_);
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
913
	}
4753 by sigra
In productionsite programs: Generalize failure handling method to result handling method. Depending on the result of the called program, the calling program can now return failed, completed or skipped. It can also chose to continue execution or repeat the call.
914
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
915
	switch (handling_methods_[program_result_index(program_result)]) {
916
	case ProgramResultHandlingMethod::kFail:
917
	case ProgramResultHandlingMethod::kComplete:
918
	case ProgramResultHandlingMethod::kSkip:
919
		return ps.program_end(game, ProgramResult::kNone);
920
	case ProgramResultHandlingMethod::kContinue:
4677 by sigra
move more of the logic files into the logic directory
921
		return ps.program_step(game);
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
922
	case ProgramResultHandlingMethod::kRepeat:
9038.1.10 by GunChleoc
Production program phases are now ProductionResults. This uncovered some suble bugs where ActSleep and ActAnimate would change the phase.
923
		ps.top_state().phase = ProgramResult::kNone;
8048 by GunChleoc
Ran clang-format.
924
		ps.program_timer_ = true;
9586 by The Widelands Bunnybot
Make `Time` and `Duration` typesafe (#4325)
925
		ps.program_time_ = ps.schedule_act(game, Duration(10));
6430 by Shevonar
Fixed more than 300 warnings found by Eclipse CDT's Code Analysis mostly
926
		break;
4677 by sigra
move more of the logic files into the logic directory
927
	}
928
}
929
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
930
/* RST
931
callworker
932
----------
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
933
.. function:: callworker=\<worker_program_name\> \[on failure fail|complete|skip\]
9471 by The Widelands Bunnybot
Program documentation (#4140)
934
935
   :arg string worker_program_name: The name of a :ref:`worker program <tribes_worker_programs>`
936
      defined in the productionsite's main :ref:`worker <lua_tribes_basic_workers>`.
937
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
938
   :arg string on: Defines what to do if the worker program fails. The production program
939
      is always terminated immediately when ``callworker`` fails; this parameter specifies
940
      what result status the production program should report. Default is ``fail``.
941
9471 by The Widelands Bunnybot
Program documentation (#4140)
942
Calls a program of the productionsite's main worker. Example:
943
944
.. code-block:: lua
945
946
      -- Productionsite program actions
947
      actions = {
948
         -- Send the farmer out to harvest wheat from a wheat field
949
         "callworker=harvest",
950
         "animate=working duration:3s",
951
         "sleep=duration:1s"
952
      }
953
954
      -- Corresponding worker program for harvesting wheat from a wheat field
955
      harvest = {
956
         "findobject=attrib:ripe_wheat radius:2",
957
         "walk=object",
958
         "playsound=sound/farm/scythe priority:70% allow_multiple",
959
         "animate=harvest duration:10s",
960
         "callobject=harvest",
961
         "animate=gather duration:4s",
962
         "createware=wheat",
963
         "return"
964
      }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
965
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
966
ProductionProgram::ActCallWorker::ActCallWorker(const std::vector<std::string>& arguments,
8749 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1733064-program-redesign:
967
                                                const std::string& production_program_name,
968
                                                ProductionSiteDescr* descr,
10462 by The Widelands Bunnybot
Clear clang-tidy in logic headers (#5691)
969
                                                const Descriptions& descriptions) {
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
970
	const size_t nr_args = arguments.size();
971
	if (nr_args != 1 && nr_args != 4) {
972
		throw GameDataError(
973
		   "Usage: callworker=<worker_program_name> [on failure fail|complete|skip]");
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
974
	}
975
976
	program_ = arguments.front();
977
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
978
	if (nr_args > 1) {
979
		if (arguments.at(1) != "on" || arguments.at(2) != "failure") {
980
			throw GameDataError("Expected 'on failure' after worker program name");
981
		}
982
		if (arguments.at(3) == "fail") {
983
			on_failure_ = ProgramResult::kFailed;
984
		} else if (arguments.at(3) == "complete") {
985
			on_failure_ = ProgramResult::kCompleted;
986
		} else if (arguments.at(3) == "skip") {
987
			on_failure_ = ProgramResult::kSkipped;
988
		} else {
989
			throw GameDataError("Expected fail|complete|skip in final position but found '%s'",
990
			                    arguments.at(3).c_str());
991
		}
992
	}
993
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
994
	//  Quote from "void ProductionSite::program_act(Game &)":
995
	//  "Always main worker is doing stuff"
996
	const WorkerDescr& main_worker_descr =
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
997
	   *descriptions.get_worker_descr(descr->working_positions().front().first);
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
998
9372 by The Widelands Bunnybot
Add optional braces to logic code (#3993)
999
	WorkerProgram const* workerprogram = main_worker_descr.get_program(program_);
1000
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1001
	//  This will fail unless the main worker has a program with the given
1002
	//  name, so it also validates the parameter.
9373 by The Widelands Bunnybot
Add optional braces to wui (#3998)
1003
	const WorkareaInfo& worker_workarea_info = workerprogram->get_workarea_info();
9372 by The Widelands Bunnybot
Add optional braces to logic code (#3993)
1004
1005
	// Add to building outputs for help and AI
1006
	for (const DescriptionIndex produced_ware : workerprogram->produced_ware_types()) {
1007
		descr->add_output_ware_type(produced_ware);
1008
	}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1009
1010
	for (const auto& area_info : worker_workarea_info) {
1011
		std::set<std::string>& building_radius_infos = descr->workarea_info_[area_info.first];
1012
1013
		for (const std::string& worker_name : area_info.second) {
1014
			std::string description = descr->name();
1015
			description += ' ';
1016
			description += production_program_name;
1017
			description += " worker ";
1018
			description += main_worker_descr.name();
1019
			description += worker_name;
1020
			building_radius_infos.insert(description);
4677 by sigra
move more of the logic files into the logic directory
1021
		}
1022
	}
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1023
9817 by The Widelands Bunnybot
Ai production support (#4618)
1024
	for (const auto& attribute_info : workerprogram->needed_attributes()) {
1025
		descr->add_needed_attribute(attribute_info);
1026
	}
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1027
	for (const auto& attribute_info : workerprogram->collected_attributes()) {
1028
		descr->add_collected_attribute(attribute_info);
1029
	}
1030
	for (const auto& attribute_info : workerprogram->created_attributes()) {
1031
		descr->add_created_attribute(attribute_info);
1032
	}
1033
	for (const std::string& resourcename : workerprogram->collected_resources()) {
9659 by The Widelands Bunnybot
Read mining information for help & AI (#4489)
1034
		// Workers always collect 100% of the resource, and then find no more
1035
		descr->add_collected_resource(resourcename, 100, 0);
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1036
	}
1037
	for (const std::string& resourcename : workerprogram->created_resources()) {
1038
		descr->add_created_resource(resourcename);
1039
	}
1040
	for (const std::string& bobname : workerprogram->created_bobs()) {
1041
		descr->add_created_bob(bobname);
1042
	}
4677 by sigra
move more of the logic files into the logic directory
1043
}
1044
8491.1.8 by GunChleoc
Renamed productionprograms:
1045
void ProductionProgram::ActCallWorker::execute(Game& game, ProductionSite& ps) const {
4677 by sigra
move more of the logic files into the logic directory
1046
	// Always main worker is doing stuff
10050 by The Widelands Bunnybot
Intelligent worker reordering (#5099)
1047
	ps.working_positions_.at(ps.main_worker_).worker.get(game)->update_task_buildingwork(game);
4677 by sigra
move more of the logic files into the logic directory
1048
}
1049
8491.1.8 by GunChleoc
Renamed productionprograms:
1050
bool ProductionProgram::ActCallWorker::get_building_work(Game& game,
8749 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1733064-program-redesign:
1051
                                                         ProductionSite& psite,
1052
                                                         Worker& worker) const {
8048 by GunChleoc
Ran clang-format.
1053
	ProductionSite::State& state = psite.top_state();
9038.1.10 by GunChleoc
Production program phases are now ProductionResults. This uncovered some suble bugs where ActSleep and ActAnimate would change the phase.
1054
	if (state.phase == ProgramResult::kNone) {
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1055
		worker.start_task_program(game, program());
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
1056
		if ((state.flags & ProductionSite::State::StateFlags::kStateFlagHasExtraData) != 0u) {
9722 by The Widelands Bunnybot
Targeted Scouting (#4493)
1057
			worker.top_state().objvar1 = state.objvar;
1058
		}
9038.1.10 by GunChleoc
Production program phases are now ProductionResults. This uncovered some suble bugs where ActSleep and ActAnimate would change the phase.
1059
		state.phase = ProgramResult::kFailed;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1060
		return true;
1061
	}
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
1062
	psite.program_step(game);
1063
	return false;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1064
}
1065
8491.1.8 by GunChleoc
Renamed productionprograms:
1066
void ProductionProgram::ActCallWorker::building_work_failed(Game& game,
8749 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1733064-program-redesign:
1067
                                                            ProductionSite& psite,
10191 by The Widelands Bunnybot
Fix misc clang-tidy checks in `logic` (#5255)
1068
                                                            Worker& /* worker */) const {
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
1069
	psite.program_end(game, on_failure_);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1070
}
1071
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1072
/* RST
1073
sleep
1074
-----
9471 by The Widelands Bunnybot
Program documentation (#4140)
1075
.. function:: sleep=duration:\<duration\>
1076
1077
   :arg duration duration: The time :ref:`map_object_programs_datatypes_duration` for which the
1078
      program will wait before continuing on to the next action. If ``0``, the result from the most
1079
      recent command that returned a value is used.
1080
1081
Blocks the execution of the program for the specified duration. Example:
1082
1083
.. code-block:: lua
1084
1085
      actions = {
1086
         "consume=ration",
1087
         -- Do nothing for 30 seconds
1088
         "sleep=duration:30s",
1089
         "callworker=scout"
1090
      }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1091
*/
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1092
ProductionProgram::ActSleep::ActSleep(const std::vector<std::string>& arguments) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1093
	if (arguments.size() != 1) {
9413 by The Widelands Bunnybot
Convert sleep program to new duration syntax (#4056)
1094
		throw GameDataError("Usage: sleep=duration:<duration>");
1095
	}
1096
	const std::pair<std::string, std::string> item = read_key_value_pair(arguments.front(), ':');
1097
	if (item.first == "duration") {
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1098
		duration_ = read_duration(item.second);
9413 by The Widelands Bunnybot
Convert sleep program to new duration syntax (#4056)
1099
	} else {
1100
		throw GameDataError(
1101
		   "Unknown argument '%s'. Usage: duration:<duration>", arguments.front().c_str());
1102
	}
4677 by sigra
move more of the logic files into the logic directory
1103
}
1104
8048 by GunChleoc
Ran clang-format.
1105
void ProductionProgram::ActSleep::execute(Game& game, ProductionSite& ps) const {
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
1106
	return ps.program_step(
1107
	   game, duration_.get() != 0u ? duration_ : Duration(0), ps.top_state().phase);
4677 by sigra
move more of the logic files into the logic directory
1108
}
1109
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1110
/* RST
1111
animate
1112
-------
9420 by The Widelands Bunnybot
Document animations (#4059)
1113
Runs an animation. See :ref:`map_object_programs_animate`.
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1114
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1115
ProductionProgram::ActAnimate::ActAnimate(const std::vector<std::string>& arguments,
9585 by The Widelands Bunnybot
Fix simple cppcheck issues (#4355)
1116
                                          ProductionSiteDescr* descr)
1117
   : parameters(MapObjectProgram::parse_act_animate(arguments, *descr, false)) {
4677 by sigra
move more of the logic files into the logic directory
1118
}
1119
8048 by GunChleoc
Ran clang-format.
1120
void ProductionProgram::ActAnimate::execute(Game& game, ProductionSite& ps) const {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1121
	ps.start_animation(game, parameters.animation);
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
1122
	return ps.program_step(game, parameters.duration.get() != 0u ? parameters.duration : Duration(0),
1123
	                       ps.top_state().phase);
4677 by sigra
move more of the logic files into the logic directory
1124
}
1125
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1126
/* RST
1127
consume
1128
-------
9471 by The Widelands Bunnybot
Program documentation (#4140)
1129
.. function:: consume=ware_name\{,ware_name\}\[:count\] \[ware_name\{,ware_name\}\[:amount\]\]...\]
1130
1131
   :arg string ware_name: a list of :ref:`ware types <lua_tribes_wares>` to choose from for
1132
      consumption. A ware type may only appear once in the command.
1133
1134
   :arg int amount: The amount of wares of the chosen type to consume. A positive integer. If
1135
      omitted, the value ``1`` is used.
1136
1137
Consumes wares from the input storages. For each ware group, the number of wares specified in
1138
``amount`` is consumed. The consumed wares may be of any type in the group.
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1139
1140
If there are not enough wares in the input storages, the command fails (with the same effect as
1141
executing ``return=failed``). Then no wares will be consumed.
1142
1143
Selecting which ware types to consume for a group so that the whole command succeeds is a constraint
1144
satisfaction problem. The implementation does not implement an exhaustive search for a solution to
1145
it. It is just a greedy algorithm which gives up instead of backtracking. Therefore the command may
1146
fail even if there is a solution.
1147
1148
However it may be possible to help the algorithm by ordering the groups carefully. Suppose that the
1149
input storage has the wares ``a:1, b:1`` and a consume command has the parameters ``a,b:1 a:1``. The
1150
algorithm tries to consume its input wares in order. It starts with the first group and consumes 1
1151
ware of type ``a`` (the group becomes satisfied). Then it proceeds with the second group, but there
1152
are no wares of type ``a`` left to consume. Since there is no other ware type that can satisfy the
1153
group, the command will fail. If the groups are reordered so that the parameters become ``a:1
1154
a,b:1``, it will work. The algorithm will consume 1 ware of type ``a`` for the first group. When it
1155
proceeds with the second group, it will not have any wares of type ``a`` left. Then it will go on
1156
and consume 1 ware of type ``b`` for the second group (which becomes satisfied) and the command
1157
succeeds.
1158
1159
.. note:: It is not possible to reorder ware types within a group. ``a,b`` is equivalent to ``b,a``
1160
    because in the internal representation the ware types of a group are sorted.
9471 by The Widelands Bunnybot
Program documentation (#4140)
1161
1162
Examples:
1163
1164
.. code-block:: lua
1165
1166
      actions = {
1167
         "return=skipped unless economy needs shield_advanced",
1168
         -- Try to consume 2x iron, then 2x coal, then 1x gold
1169
         "consume=iron:2 coal:2 gold",
1170
         "sleep=duration:32s",
1171
         "animate=working duration:45s",
1172
         "produce=shield_advanced"
1173
      },
1174
1175
      actions = {
1176
         "checksoldier=soldier:evade level:0",
1177
         "return=failed unless site has empire_bread",
1178
         "return=failed unless site has fish,meat",
1179
         "sleep=duration:30s",
1180
         "checksoldier=soldier:evade level:0",
1181
         -- Try to consume 1x empire_bread, then 1x fish or 1x meat
1182
         "consume=empire_bread fish,meat",
1183
         "train=soldier:evade level:1"
1184
      }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1185
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1186
ProductionProgram::ActConsume::ActConsume(const std::vector<std::string>& arguments,
8048 by GunChleoc
Ran clang-format.
1187
                                          const ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1188
                                          const Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1189
	if (arguments.empty()) {
1190
		throw GameDataError(
1191
		   "Usage: consume=<ware or worker>[,<ware or worker>[,...]][:<amount>] ...");
4677 by sigra
move more of the logic files into the logic directory
1192
	}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1193
	consumed_wares_workers_ =
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1194
	   parse_ware_type_groups(arguments.begin(), arguments.end(), descr, descriptions);
4677 by sigra
move more of the logic files into the logic directory
1195
}
1196
8048 by GunChleoc
Ran clang-format.
1197
void ProductionProgram::ActConsume::execute(Game& game, ProductionSite& ps) const {
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
1198
	std::vector<InputQueue*> const inputqueues = ps.inputqueues();
1199
	std::vector<uint8_t> consumption_quantities(inputqueues.size(), 0);
6662 by Holger Rapp
Removed use of HAVE_VARARRAY. It is against the standard and we should not rely on it being there. Avoiding its use is simple and should be preferred.
1200
7175.17.53 by GunChleoc
Renamed consumed_wares to consumed_wares_workers. Tweaks to help strings.
1201
	Groups l_groups = consumed_wares_workers_;  //  make a copy for local modification
4677 by sigra
move more of the logic files into the logic directory
1202
1203
	//  Iterate over all input queues and see how much we should consume from
1204
	//  each of them.
7175.17.2 by Notabilis
Implemented WorkersQueue.
1205
	bool found;
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
1206
	for (size_t i = 0; i < inputqueues.size(); ++i) {
1207
		DescriptionIndex const input_index = inputqueues[i]->get_index();
1208
		WareWorker const input_type = inputqueues[i]->get_type();
1209
		uint8_t nr_available = inputqueues[i]->get_filled();
1210
		consumption_quantities[i] = 0;
4677 by sigra
move more of the logic files into the logic directory
1211
1212
		//  Iterate over all consume groups and see if they want us to consume
1213
		//  any thing from the currently considered input queue.
7175.17.2 by Notabilis
Implemented WorkersQueue.
1214
		for (Groups::iterator it = l_groups.begin(); it != l_groups.end();) {
1215
			found = false;
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
1216
			for (auto input_it = it->first.begin(); input_it != it->first.end(); input_it++) {
1217
				if (input_it->first == input_index && input_it->second == input_type) {
7175.17.2 by Notabilis
Implemented WorkersQueue.
1218
					found = true;
1219
					if (it->second <= nr_available) {
1220
						//  There are enough wares of the currently considered type
1221
						//  to fulfill the requirements of the current group. We can
1222
						//  therefore erase the group.
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
1223
						consumption_quantities[i] += it->second;
7175.17.3 by Notabilis
Merge with trunk.
1224
						nr_available -= it->second;
7175.17.2 by Notabilis
Implemented WorkersQueue.
1225
						it = l_groups.erase(it);
1226
						//  No increment here, erase moved next element to the position
1227
						//  pointed to by it.
1228
					} else {
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
1229
						consumption_quantities[i] += nr_available;
7175.17.3 by Notabilis
Merge with trunk.
1230
						it->second -= nr_available;
7175.17.13 by GunChleoc
clang-format.
1231
						++it;  //  Now check if the next group includes this ware type.
7175.17.2 by Notabilis
Implemented WorkersQueue.
1232
					}
1233
					break;
1234
				}
1235
			}
1236
			// group does not request ware
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1237
			if (!found) {
7175.17.2 by Notabilis
Implemented WorkersQueue.
1238
				++it;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1239
			}
7175.17.2 by Notabilis
Implemented WorkersQueue.
1240
		}
1241
	}
1242
7150.5.10 by fios at foramnagaidhlig
Changed the wording of some strings so they can work together with the tribes' conf files
1243
	// "Did not start working because .... is/are missing"
4729 by sigra
Fix initialization order for Widelands::Building::m_global. Implement a tooltip for buildings that shows the result of a productionsite. If a productionsite returns from a production program because of a condition, fails a program because of missing wares to consume, or produces something, this is shown in the tooltip. It can be turned off in the config file with "building_tooltip_format=" (or "--building_tooltip_format= " on the command line).
1244
	if (uint8_t const nr_missing_groups = l_groups.size()) {
8048 by GunChleoc
Ran clang-format.
1245
		const TribeDescr& tribe = ps.owner().tribe();
7150.5.6 by fios at foramnagaidhlig
Reworked string output in ProductionProgram::ActConsume::execute
1246
1247
		std::vector<std::string> group_list;
7870.2.1 by fios at foramnagaidhlig
Use auto to iterate maps.
1248
		for (const auto& group : l_groups) {
9631 by The Widelands Bunnybot
Clear readability-container-size-empty (#4445)
1249
			assert(!group.first.empty());
7150.5.6 by fios at foramnagaidhlig
Reworked string output in ProductionProgram::ActConsume::execute
1250
1251
			std::vector<std::string> ware_list;
7175.17.2 by Notabilis
Implemented WorkersQueue.
1252
			for (const auto& entry : group.first) {
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
1253
				ware_list.push_back(entry.second == wwWARE ?
9939 by The Widelands Bunnybot
GitHub action updates (#4735)
1254
                                   tribe.get_ware_descr(entry.first)->descname() :
1255
                                   tribe.get_worker_descr(entry.first)->descname());
7150.5.6 by fios at foramnagaidhlig
Reworked string output in ProductionProgram::ActConsume::execute
1256
			}
7375.1.3 by fios at foramnagaidhlig
Renamed i18n::localize_item_list to i18n::localize_list.
1257
			std::string ware_string = i18n::localize_list(ware_list, i18n::ConcatenateWith::OR);
7150.5.6 by fios at foramnagaidhlig
Reworked string output in ProductionProgram::ActConsume::execute
1258
1259
			uint8_t const count = group.second;
1260
			if (1 < count) {
1261
				ware_string =
8048 by GunChleoc
Ran clang-format.
1262
				   /** TRANSLATORS: e.g. 'Did not start working because 3x water and 3x wheat are
1263
				      missing' */
1264
				   /** TRANSLATORS: For this example, this is what's in the place holders: */
1265
				   /** TRANSLATORS:    %1$i = "3" */
1266
				   /** TRANSLATORS:    %2$s = "water" */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1267
				   format(_("%1$ix %2$s"), static_cast<unsigned int>(count), ware_string);
7150.5.6 by fios at foramnagaidhlig
Reworked string output in ProductionProgram::ActConsume::execute
1268
			}
1269
			group_list.push_back(ware_string);
1270
		}
1271
7185.1.2 by fios at foramnagaidhlig
Changed a string to const
1272
		const std::string is_missing_string =
8048 by GunChleoc
Ran clang-format.
1273
		   /** TRANSLATORS: e.g. 'Did not start working because 3x water and 3x wheat are missing' */
1274
		   /** TRANSLATORS: e.g. 'Did not start working because fish, meat or pitta bread is missing'
8939 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/appveyor_reenable_glbinding:
1275
		    */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1276
		   format(ngettext("%s is missing", "%s are missing", nr_missing_groups),
1277
		          i18n::localize_list(group_list, i18n::ConcatenateWith::AND));
7185.1.1 by fios at foramnagaidhlig
Small stringfix for production programs
1278
6810.2.16 by GunChleoc
Cleaned up code to comply with codecheck. No changes in functionality whatsoever.
1279
		std::string result_string =
8048 by GunChleoc
Ran clang-format.
1280
		   /** TRANSLATORS: e.g. 'Did not start working because 3x water and 3x wheat are missing' */
1281
		   /** TRANSLATORS: For this example, this is what's in the place holders: */
1282
		   /** TRANSLATORS:    %1$s = "working" */
1283
		   /** TRANSLATORS:    %2$s = "3x water and 3x wheat are missing" */
1284
		   /** TRANSLATORS: This appears in the hover text on buildings. Please test these in
1285
		      context*/
1286
		   /** TRANSLATORS: on a development build if you can, and let us know if there are any issues
8939 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/appveyor_reenable_glbinding:
1287
		    */
8048 by GunChleoc
Ran clang-format.
1288
		   /** TRANSLATORS: we need to address for your language. */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1289
		   format(_("Did not start %1$s because %2$s"), ps.top_state().program->descname(),
1290
		          is_missing_string);
9089.1.2 by Toni Förster
do proper string comparison & add some logging
1291
9090 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1489295-mine-is-exhausted:
1292
		if (ps.production_result() != ps.descr().out_of_resource_heading() ||
1293
		    ps.descr().out_of_resource_heading().empty()) {
9089.1.1 by Toni Förster
when main vein is exhausted, don't show tooltip for missing food
1294
			ps.set_production_result(result_string);
1295
		}
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1296
		return ps.program_end(game, ProgramResult::kFailed);
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
1297
	}
1298
	//  we fulfilled all consumption requirements
1299
	for (size_t i = 0; i < inputqueues.size(); ++i) {
1300
		if (uint8_t const q = consumption_quantities[i]) {
1301
			assert(q <= inputqueues[i]->get_filled());
1302
			inputqueues[i]->set_filled(inputqueues[i]->get_filled() - q);
6037.2.4 by borim
* temporary disable writing the consumed statistic to the file. some questions are open about reading the statistic file again.
1303
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
1304
			// Update consumption statistics
1305
			if (inputqueues[i]->get_type() == wwWARE) {
1306
				ps.get_owner()->ware_consumed(inputqueues[i]->get_index(), q);
7175.18.1 by Notabilis
Refactoring. Using InputQueue instead of Wares-/WorkersQueue where it makes sense.
1307
			}
7175.17.46 by GunChleoc
Codereview.
1308
		}
4729 by sigra
Fix initialization order for Widelands::Building::m_global. Implement a tooltip for buildings that shows the result of a productionsite. If a productionsite returns from a production program because of a condition, fails a program because of missing wares to consume, or produces something, this is shown in the tooltip. It can be turned off in the config file with "building_tooltip_format=" (or "--building_tooltip_format= " on the command line).
1309
	}
9680 by The Widelands Bunnybot
'src/editor/editorinteractive.h' was automatically formatted.
1310
	return ps.program_step(game);
4677 by sigra
move more of the logic files into the logic directory
1311
}
1312
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1313
/* RST
1314
produce
1315
-------
9471 by The Widelands Bunnybot
Program documentation (#4140)
1316
.. function:: produce=\<ware_name\>\[:\<amount\>\] \[\<ware_name\>\[:\<amount\>\]...\]
1317
1318
   :arg string ware_name: The name of a :ref:`ware type <lua_tribes_wares>`. A ware
1319
      type may only appear once in the command.
1320
1321
   :arg int amount: The amount of wares of this type to produce. A positive integer. If omitted,
1322
      the value ``1`` is used.
1323
1324
Produces wares. For each group, the number of wares specified in ``amount`` is produced and then
1325
placed on the building's flag to be carried where they are needed. The produced wares are of the
1326
type specified by
1327
``ware_name`` in the group. Example:
1328
1329
.. code-block:: lua
1330
1331
      actions = {
1332
         "return=skipped unless economy needs fur",
1333
         "consume=barley water",
1334
         "sleep=duration:15s",
1335
         "animate=working duration:20s",
1336
         -- Produce 2x fur and 1x meat
1337
         "produce=fur:2 meat"
1338
      }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1339
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1340
ProductionProgram::ActProduce::ActProduce(const std::vector<std::string>& arguments,
9372 by The Widelands Bunnybot
Add optional braces to logic code (#3993)
1341
                                          ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1342
                                          Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1343
	if (arguments.empty()) {
1344
		throw GameDataError("Usage: produce=<ware name>[:<amount>] [<ware name>[:<amount>]...]");
4677 by sigra
move more of the logic files into the logic directory
1345
	}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1346
	produced_wares_ = parse_bill_of_materials(arguments, WareWorker::wwWARE, descriptions);
9372 by The Widelands Bunnybot
Add optional braces to logic code (#3993)
1347
1348
	// Add to building outputs for help and AI
1349
	for (auto& produced_ware : produced_wares_) {
1350
		descr.add_output_ware_type(produced_ware.first);
1351
	}
4677 by sigra
move more of the logic files into the logic directory
1352
}
1353
8048 by GunChleoc
Ran clang-format.
1354
void ProductionProgram::ActProduce::execute(Game& game, ProductionSite& ps) const {
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
1355
	assert(ps.produced_wares_.empty());
1356
	ps.produced_wares_ = produced_wares_;
10050 by The Widelands Bunnybot
Intelligent worker reordering (#5099)
1357
	ps.working_positions_.at(ps.main_worker_).worker.get(game)->update_task_buildingwork(game);
4729 by sigra
Fix initialization order for Widelands::Building::m_global. Implement a tooltip for buildings that shows the result of a productionsite. If a productionsite returns from a production program because of a condition, fails a program because of missing wares to consume, or produces something, this is shown in the tooltip. It can be turned off in the config file with "building_tooltip_format=" (or "--building_tooltip_format= " on the command line).
1358
8048 by GunChleoc
Ran clang-format.
1359
	const TribeDescr& tribe = ps.owner().tribe();
9631 by The Widelands Bunnybot
Clear readability-container-size-empty (#4445)
1360
	assert(!produced_wares_.empty());
4969.1.1 by Jari Hautio
Compiles and runs under VS2008. Ues boost::sub_range.
1361
7125.2.31 by Holger Rapp
Two more wl_ranges down.
1362
	std::vector<std::string> ware_descnames;
7650.2.1 by fios at foramnagaidhlig
Fixed compiler warning in gcc 5.2.0.
1363
	uint8_t count = 0;
7175.14.2 by fios at foramnagaidhlig
- Added new functions produced/consumed wares to ProductionProgram::Action.
1364
	for (const auto& item_pair : produced_wares_) {
7650.2.2 by fios at foramnagaidhlig
Fixed summing up of wares/workers for ngettext in productionprogam.
1365
		count += item_pair.second;
7150.5.29 by GunChleoc \
Some refactoring and NOCOM questions
1366
		std::string ware_descname = tribe.get_ware_descr(item_pair.first)->descname();
7624.1.20 by fios at foramnagaidhlig
Fixed numbering inconsistency in production program strings.
1367
		if (1 < item_pair.second || 1 < produced_wares_.size()) {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1368
			ware_descname = format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
1369
			   /** TRANSLATORS: This is an item in a list of wares, e.g. "Produced 2x Coal": */
1370
			   /** TRANSLATORS:    %1$i = "2" */
1371
			   /** TRANSLATORS:    %2$s = "Coal" */
1372
			   _("%1$ix %2$s"), static_cast<unsigned int>(item_pair.second), ware_descname);
4729 by sigra
Fix initialization order for Widelands::Building::m_global. Implement a tooltip for buildings that shows the result of a productionsite. If a productionsite returns from a production program because of a condition, fails a program because of missing wares to consume, or produces something, this is shown in the tooltip. It can be turned off in the config file with "building_tooltip_format=" (or "--building_tooltip_format= " on the command line).
1373
		}
7125.2.31 by Holger Rapp
Two more wl_ranges down.
1374
		ware_descnames.push_back(ware_descname);
4729 by sigra
Fix initialization order for Widelands::Building::m_global. Implement a tooltip for buildings that shows the result of a productionsite. If a productionsite returns from a production program because of a condition, fails a program because of missing wares to consume, or produces something, this is shown in the tooltip. It can be turned off in the config file with "building_tooltip_format=" (or "--building_tooltip_format= " on the command line).
1375
	}
7375.1.3 by fios at foramnagaidhlig
Renamed i18n::localize_item_list to i18n::localize_list.
1376
	std::string ware_list = i18n::localize_list(ware_descnames, i18n::ConcatenateWith::AND);
7125.2.31 by Holger Rapp
Two more wl_ranges down.
1377
8071 by GunChleoc
Fetched translations and updated catalogues.
1378
	const std::string result_string =
1379
	   /** TRANSLATORS: %s is a list of wares. String is fetched according to total amount of
1380
	      wares. */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1381
	   format(ngettext("Produced %s", "Produced %s", count), ware_list);
9090 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1489295-mine-is-exhausted:
1382
	if (ps.production_result() != ps.descr().out_of_resource_heading() ||
1383
	    ps.descr().out_of_resource_heading().empty()) {
9089.1.4 by hessenfarmer
suppressed also the "produced ..." and the "did not start cause the economy doesn't need..." message if a valid out of ressource message is set.
1384
		ps.set_production_result(result_string);
1385
	}
4677 by sigra
move more of the logic files into the logic directory
1386
}
1387
8048 by GunChleoc
Ran clang-format.
1388
bool ProductionProgram::ActProduce::get_building_work(Game& game,
1389
                                                      ProductionSite& psite,
1390
                                                      Worker& /* worker */) const {
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1391
	// We reach this point once all wares have been carried outside the building
1392
	psite.program_step(game);
1393
	return false;
1394
}
1395
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1396
/* RST
1397
recruit
1398
-------
9471 by The Widelands Bunnybot
Program documentation (#4140)
1399
.. function:: recruit=\<worker_name\>\[:\<amount\>\] \[\<worker_name\>\[:\<amount\>\]...\]
1400
1401
   :arg string worker_name: The name of a :ref:`worker type <lua_tribes_basic_workers>`. A worker
1402
      type may only appear once in the command.
1403
1404
   :arg int amount: The amount of workers of this type to create. A positive integer. If omitted,
1405
      the value ``1`` is used.
1406
1407
Produces workers. For each group, the number of workers specified in ``amount`` is produced, which
1408
then leave the site looking for employment. The produced workers are of the type specified by
1409
``worker_name`` in the group. Example:
1410
1411
.. code-block:: lua
1412
1413
      actions = {
1414
         "return=skipped unless economy needs atlanteans_horse",
1415
         "consume=corn water",
1416
         "sleep=duration:15s",
1417
         "playsound=sound/farm/horse priority:50% allow_multiple",
1418
         "animate=working duration:15s",
1419
         -- Create 2 horses
1420
         "recruit=atlanteans_horse:2"
1421
      }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1422
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1423
ProductionProgram::ActRecruit::ActRecruit(const std::vector<std::string>& arguments,
9372 by The Widelands Bunnybot
Add optional braces to logic code (#3993)
1424
                                          ProductionSiteDescr& descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1425
                                          Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1426
	if (arguments.empty()) {
9471 by The Widelands Bunnybot
Program documentation (#4140)
1427
		throw GameDataError("Usage: recruit=<worker_name>[:<amount>] [<worker_name>[:<amount>]...]");
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
1428
	}
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1429
	recruited_workers_ = parse_bill_of_materials(arguments, WareWorker::wwWORKER, descriptions);
9372 by The Widelands Bunnybot
Add optional braces to logic code (#3993)
1430
1431
	// Add to building outputs for help and AI
1432
	for (auto& recruited_worker : recruited_workers_) {
1433
		descr.add_output_worker_type(recruited_worker.first);
1434
	}
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
1435
}
1436
8048 by GunChleoc
Ran clang-format.
1437
void ProductionProgram::ActRecruit::execute(Game& game, ProductionSite& ps) const {
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
1438
	assert(ps.recruited_workers_.empty());
1439
	ps.recruited_workers_ = recruited_workers_;
10050 by The Widelands Bunnybot
Intelligent worker reordering (#5099)
1440
	ps.working_positions_.at(ps.main_worker_).worker.get(game)->update_task_buildingwork(game);
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
1441
8048 by GunChleoc
Ran clang-format.
1442
	const TribeDescr& tribe = ps.owner().tribe();
9631 by The Widelands Bunnybot
Clear readability-container-size-empty (#4445)
1443
	assert(!recruited_workers_.empty());
7125.2.31 by Holger Rapp
Two more wl_ranges down.
1444
	std::vector<std::string> worker_descnames;
7650.2.1 by fios at foramnagaidhlig
Fixed compiler warning in gcc 5.2.0.
1445
	uint8_t count = 0;
7175.14.2 by fios at foramnagaidhlig
- Added new functions produced/consumed wares to ProductionProgram::Action.
1446
	for (const auto& item_pair : recruited_workers_) {
7650.2.2 by fios at foramnagaidhlig
Fixed summing up of wares/workers for ngettext in productionprogam.
1447
		count += item_pair.second;
7150.5.29 by GunChleoc \
Some refactoring and NOCOM questions
1448
		std::string worker_descname = tribe.get_worker_descr(item_pair.first)->descname();
7624.1.20 by fios at foramnagaidhlig
Fixed numbering inconsistency in production program strings.
1449
		if (1 < item_pair.second || 1 < recruited_workers_.size()) {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1450
			worker_descname = format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
1451
			   /** TRANSLATORS: This is an item in a list of workers, e.g. "Recruited 2x Ox": */
1452
			   /** TRANSLATORS:    %1$i = "2" */
1453
			   /** TRANSLATORS:    %2$s = "Ox" */
1454
			   _("%1$ix %2$s"), static_cast<unsigned int>(item_pair.second), worker_descname);
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
1455
		}
7125.2.31 by Holger Rapp
Two more wl_ranges down.
1456
		worker_descnames.push_back(worker_descname);
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
1457
	}
7375.1.3 by fios at foramnagaidhlig
Renamed i18n::localize_item_list to i18n::localize_list.
1458
	std::string unit_string = i18n::localize_list(worker_descnames, i18n::ConcatenateWith::AND);
7125.2.31 by Holger Rapp
Two more wl_ranges down.
1459
7649 by fios at foramnagaidhlig
Fixed codecheck.
1460
	const std::string result_string =
8048 by GunChleoc
Ran clang-format.
1461
	   /** TRANSLATORS: %s is a list of workers. String is fetched according to total amount of
1462
	      workers. */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1463
	   format(ngettext("Recruited %s", "Recruited %s", count), unit_string);
7225.1.2 by fios at foramnagaidhlig
Removed all direct usaged of c_str() in conjunction with boost::format
1464
	ps.set_production_result(result_string);
4835 by sigra
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.
1465
}
1466
8048 by GunChleoc
Ran clang-format.
1467
bool ProductionProgram::ActRecruit::get_building_work(Game& game,
1468
                                                      ProductionSite& psite,
1469
                                                      Worker& /* worker */) const {
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1470
	// We reach this point once all recruits have been guided outside the building
1471
	psite.program_step(game);
1472
	return false;
1473
}
1474
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1475
/* RST
1476
mine
1477
----
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1478
9851 by The Widelands Bunnybot
Fix documentation 3 (#4798)
1479
.. function:: mine=\<resource_name\> radius:\<number\> yield:\<percent\> when_empty:\<percent\>
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
1480
     \[experience_on_fail:\<percent\>\] [no_notify]
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1481
1482
   :arg string resource_name: The name of the resource to mine, e.g. 'coal' or 'water'.
1483
   :arg int radius: The workarea radius that is searched for resources. Must be ``>0``.
1484
   :arg percent yield: The :ref:`map_object_programs_datatypes_percent` of resources that the
1485
      mine can dig up before its resource is depleted.
1486
   :arg percent when_empty: The :ref:`map_object_programs_datatypes_percent` chance that the mine
1487
      will still find some resources after it has been depleted.
1488
   :arg percent experience_on_fail: The :ref:`map_object_programs_datatypes_percent` chance that the
1489
      mine's workers will still gain some experience when mining fails after its resources have been
1490
      depleted.
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
1491
   :arg empty no_notify: Do not send a message to the player if this step fails.
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1492
1493
   Takes resources from the ground. A building that mines will deplete when the percentage of
1494
   resources given in ``resources`` has been dug up, leaving a chance of ``depleted`` that it
1495
   will still find some resources anyway. Examples:
1496
1497
.. code-block:: lua
1498
1499
     actions = {
1500
         "return=skipped unless economy needs iron_ore",
1501
         "consume=ration",
1502
         "sleep=duration:45s",
1503
         "animate=working duration:20s",
1504
          -- Search radius of 2 for iron. Will always find iron until 33.33% of it has been dug up.
1505
          -- After that, there's still a chance of 5% for finding iron.
1506
          -- If this fails, the workers still have a chance of 17% of gaining experience.
9479 by The Widelands Bunnybot
Load world units on demand (#4148)
1507
         "mine=resource_iron radius:2 yield:33.33% when_empty:5% experience_on_fail:17%",
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1508
         "produce=iron_ore"
1509
     }
1510
1511
     actions = {
1512
         "sleep=duration:20s",
1513
         "animate=working duration:20s",
1514
          -- Search radius of 1 for water. Will always find water until 100% of it has been drawn.
1515
          -- After that, there's still a chance of 65% for finding water.
9479 by The Widelands Bunnybot
Load world units on demand (#4148)
1516
         "mine=resource_water radius:1 yield:100% when_empty:65%",
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1517
         "produce=water"
1518
     }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1519
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1520
ProductionProgram::ActMine::ActMine(const std::vector<std::string>& arguments,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1521
                                    Descriptions& descriptions,
8048 by GunChleoc
Ran clang-format.
1522
                                    const std::string& production_program_name,
10462 by The Widelands Bunnybot
Clear clang-tidy in logic headers (#5691)
1523
                                    ProductionSiteDescr* descr) {
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
1524
	if (arguments.size() > 6 || arguments.size() < 4) {
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1525
		throw GameDataError("Usage: mine=<resource name> radius:<number> yield:<percent> "
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
1526
		                    "when_empty:<percent> [experience:<percent>] [no_notify]");
4677 by sigra
move more of the logic files into the logic directory
1527
	}
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1528
	experience_chance_ = 0U;
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1529
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1530
	for (const std::string& argument : arguments) {
1531
		const std::pair<std::string, std::string> item = read_key_value_pair(argument, ':');
1532
		if (item.second.empty()) {
1533
			// The safeguard is for the case that someone creates a resource called "no_notify"
1534
			if (item.first == "no_notify" && resource_ != INVALID_INDEX) {
1535
				notify_on_failure_ = false;
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1536
			} else {
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1537
				resource_ = descriptions.load_resource(item.first);
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1538
			}
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1539
		} else if (item.first == "radius") {
1540
			workarea_ = read_positive(item.second);
1541
		} else if (item.first == "yield") {
1542
			max_resources_ = math::read_percent_to_int(item.second);
1543
		} else if (item.first == "when_empty") {
1544
			depleted_chance_ = math::read_percent_to_int(item.second);
1545
		} else if (item.first == "experience_on_fail") {
1546
			experience_chance_ = math::read_percent_to_int(item.second);
1547
		} else {
1548
			throw GameDataError("Unknown argument '%s'. Usage: mine=<resource name> radius:<number> "
1549
			                    "yield:<percent> when_empty:<percent> [experience_on_fail:<percent>]",
1550
			                    item.first.c_str());
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1551
		}
1552
	}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1553
1554
	const std::string description = descr->name() + " " + production_program_name + " mine " +
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1555
	                                descriptions.get_resource_descr(resource_)->name();
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1556
	descr->workarea_info_[workarea_].insert(description);
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1557
9659 by The Widelands Bunnybot
Read mining information for help & AI (#4489)
1558
	descr->add_collected_resource(arguments.front(), max_resources_, depleted_chance_);
4677 by sigra
move more of the logic files into the logic directory
1559
}
1560
8048 by GunChleoc
Ran clang-format.
1561
void ProductionProgram::ActMine::execute(Game& game, ProductionSite& ps) const {
8429.2.1 by Holger Rapp
Cleanups map handling in EditorGameBase
1562
	Map* map = game.mutable_map();
4677 by sigra
move more of the logic files into the logic directory
1563
1564
	//  select one of the nodes randomly
8048 by GunChleoc
Ran clang-format.
1565
	uint32_t totalres = 0;
4677 by sigra
move more of the logic files into the logic directory
1566
	uint32_t totalchance = 0;
8048 by GunChleoc
Ran clang-format.
1567
	uint32_t totalstart = 0;
4677 by sigra
move more of the logic files into the logic directory
1568
1569
	{
8048 by GunChleoc
Ran clang-format.
1570
		MapRegion<Area<FCoords>> mr(
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1571
		   *map, Area<FCoords>(map->get_fcoords(ps.get_position()), workarea_));
4677 by sigra
move more of the logic files into the logic directory
1572
		do {
7838.2.4 by fios at foramnagaidhlig
More consistent use of DescriptionIndex and ResourceAmount.
1573
			DescriptionIndex fres = mr.location().field->get_resources();
1574
			ResourceAmount amount = mr.location().field->get_resources_amount();
8048 by GunChleoc
Ran clang-format.
1575
			ResourceAmount start_amount = mr.location().field->get_initial_res_amount();
4677 by sigra
move more of the logic files into the logic directory
1576
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
1577
			if (fres != resource_) {
8048 by GunChleoc
Ran clang-format.
1578
				amount = 0;
4677 by sigra
move more of the logic files into the logic directory
1579
				start_amount = 0;
1580
			}
1581
8048 by GunChleoc
Ran clang-format.
1582
			totalres += amount;
1583
			totalstart += start_amount;
4677 by sigra
move more of the logic files into the logic directory
1584
			totalchance += 8 * amount;
1585
8764.1.13 by hessenfarmer
fixed trailing whitespaces
1586
			// Add penalty for fields that are running out
1587
			// Except for totally depleted fields or wrong ressource fields
1588
			// if we already know there is no ressource (left) we won't mine there
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1589
			if (amount == 0) {
8764.1.9 by hessenfarmer
removed mining chance penalty for depleted fields or fields with wrong ressource
1590
				totalchance += 0;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1591
			} else if (amount <= 2) {
4677 by sigra
move more of the logic files into the logic directory
1592
				totalchance += 6;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1593
			} else if (amount <= 4) {
4677 by sigra
move more of the logic files into the logic directory
1594
				totalchance += 4;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1595
			} else if (amount <= 6) {
4677 by sigra
move more of the logic files into the logic directory
1596
				totalchance += 2;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1597
			}
8429.2.1 by Holger Rapp
Cleanups map handling in EditorGameBase
1598
		} while (mr.advance(*map));
4677 by sigra
move more of the logic files into the logic directory
1599
	}
1600
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1601
	//  how much is dug
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
1602
	unsigned dug_percentage = math::k100PercentAsInt;
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
1603
	if (totalstart != 0u) {
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
1604
		dug_percentage = (totalstart - totalres) * math::k100PercentAsInt / totalstart;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1605
	}
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
1606
	if (totalres == 0u) {
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
1607
		dug_percentage = math::k100PercentAsInt;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1608
	}
4677 by sigra
move more of the logic files into the logic directory
1609
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1610
	if (dug_percentage < max_resources_) {
4677 by sigra
move more of the logic files into the logic directory
1611
		//  mine can produce normally
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1612
		if (totalres == 0) {
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1613
			return ps.program_end(game, ProgramResult::kFailed);
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1614
		}
4677 by sigra
move more of the logic files into the logic directory
1615
1616
		//  second pass through nodes
1617
		assert(totalchance);
7162.2.2 by Hans Joachim Desserud
Reduced scope of variable
1618
		int32_t pick = game.logic_rand() % totalchance;
4677 by sigra
move more of the logic files into the logic directory
1619
1620
		{
8048 by GunChleoc
Ran clang-format.
1621
			MapRegion<Area<FCoords>> mr(
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1622
			   *map, Area<FCoords>(map->get_fcoords(ps.get_position()), workarea_));
4677 by sigra
move more of the logic files into the logic directory
1623
			do {
7838.2.4 by fios at foramnagaidhlig
More consistent use of DescriptionIndex and ResourceAmount.
1624
				DescriptionIndex fres = mr.location().field->get_resources();
1625
				ResourceAmount amount = mr.location().field->get_resources_amount();
4677 by sigra
move more of the logic files into the logic directory
1626
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1627
				if (fres != resource_) {
4677 by sigra
move more of the logic files into the logic directory
1628
					amount = 0;
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1629
				}
4677 by sigra
move more of the logic files into the logic directory
1630
1631
				pick -= 8 * amount;
1632
				if (pick < 0) {
1633
					assert(amount > 0);
1634
1635
					--amount;
8429.2.1 by Holger Rapp
Cleanups map handling in EditorGameBase
1636
					map->set_resources(mr.location(), amount);
4677 by sigra
move more of the logic files into the logic directory
1637
					break;
1638
				}
8429.2.1 by Holger Rapp
Cleanups map handling in EditorGameBase
1639
			} while (mr.advance(*map));
4677 by sigra
move more of the logic files into the logic directory
1640
		}
1641
7162.2.2 by Hans Joachim Desserud
Reduced scope of variable
1642
		if (pick >= 0) {
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1643
			return ps.program_end(game, ProgramResult::kFailed);
7162.2.2 by Hans Joachim Desserud
Reduced scope of variable
1644
		}
4677 by sigra
move more of the logic files into the logic directory
1645
1646
	} else {
4826 by timowi
added messages for mines running empty (patch by andi)
1647
		//  Inform the player about an empty mine, unless
1648
		//  there is a sufficiently high chance, that the mine
1649
		//  will still produce enough.
7807.2.1 by fios at foramnagaidhlig
Renamed member variables in src/logic/map_objects/tribes for partially_finished_building - requirements.
1650
		//  e.g. mines have chance=5, wells have 65
10089 by The Widelands Bunnybot
Extend productionsite/worker program failure handling (#5146)
1651
		if (notify_on_failure_ && depleted_chance_ <= 20 * math::k100PercentAsInt / 100U) {
8048 by GunChleoc
Ran clang-format.
1652
			ps.notify_player(game, 60);
5962 by Nasenbaer
Added empty state for mines - once a mine is empty, the default animation will be set from 'idle' to 'empty', which is basically the same animation, just with an additional sign on the mine's wall showing a big black cross.
1653
			// and change the default animation
1654
			ps.set_default_anim("empty");
1655
		}
4827 by timowi
fix style and remove debug log for last commit
1656
4677 by sigra
move more of the logic files into the logic directory
1657
		//  Mine has reached its limits, still try to produce something but
1658
		//  independent of sourrunding resources. Do not decrease resources
1659
		//  further.
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
1660
		if (depleted_chance_ <= game.logic_rand() % math::k100PercentAsInt) {
7150.5.17 by fios at foramnagaidhlig
"Can’t find any more resources!" hover text for mines now uses the message title text from the conf files, if available. Added same hover text in ProductionSite::worker_failed_to_find_resource for quarries, farms etc.
1661
6933.2.5 by Teppo \
Miner in an exhausted mine gains now experience with a small probability.
1662
			// Gain experience
9447 by The Widelands Bunnybot
Use named parameters in ActMine (#4099)
1663
			if (experience_chance_ > 0 &&
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
1664
			    experience_chance_ >= game.logic_rand() % math::k100PercentAsInt) {
8048 by GunChleoc
Ran clang-format.
1665
				ps.train_workers(game);
6933.2.5 by Teppo \
Miner in an exhausted mine gains now experience with a small probability.
1666
			}
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1667
			return ps.program_end(game, ProgramResult::kFailed);
5537 by Nasenbaer
Do not show "skipped work", etc. in statistics string of a building, as it is already shown in the hover message, it clutters the screen and hides the real statistics; add hover message that indicates that a mine is empty; fixed a string with boost::format to make it better translateable; added a TODO comment to a part, where boost::format should definitley be used; updated pot files
1668
		}
4677 by sigra
move more of the logic files into the logic directory
1669
	}
1670
1671
	//  done successful
7125.3.6 by fios at foramnagaidhlig
Fixed up missing colons and removed all flagged up lines except for 1 empty comment
1672
	//  TODO(unknown): Should pass the time it takes to mine in the phase parameter of
7125.1.1 by fios at foramnagaidhlig
Cleaned up TODO/FIXME/BUG comments
1673
	//  ProductionSite::program_step so that the following sleep/animate
1674
	//  command knows how long it should last.
4677 by sigra
move more of the logic files into the logic directory
1675
	return ps.program_step(game);
1676
}
1677
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1678
/* RST
1679
checksoldier
1680
------------
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1681
.. function:: checksoldier=soldier:attack|defense|evade|health level:\<number\>
1682
1683
   :arg string soldier: The soldier training attribute to check for.
1684
1685
   :arg int level: The level that the soldier should have for the given training attribute.
1686
9471 by The Widelands Bunnybot
Program documentation (#4140)
1687
.. note:: This action is only available to :ref:`training sites
1688
   <lua_tribes_buildings_trainingsites>`.
1689
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1690
Returns failure unless there is a soldier present with the given training attribute at the given
1691
level.
1692
1693
.. note:: The program's name must match the attribute to be trained and the level checked for, in
1694
   the form ``upgrade_soldier_<attribute>_<level>``.
1695
1696
Example:
1697
1698
.. code-block:: lua
1699
1700
      upgrade_soldier_attack_3 = {
1701
         -- TRANSLATORS: Completed/Skipped/Did not start upgrading ... because ...
10154 by The Widelands Bunnybot
Fix Remaining Optional Lua Parentheses (#5226)
1702
         descname = _("upgrading soldier attack from level 3 to level 4"),
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1703
         actions = {
1704
            -- Fails when there aren't any soldiers with attack level 3
1705
            "checksoldier=soldier:attack level:3",
1706
            "return=failed unless site has sword_long",
1707
            "return=failed unless site has honey_bread,mead",
1708
            "return=failed unless site has smoked_fish,smoked_meat",
1709
            "sleep=duration:10s800ms",
1710
            "animate=working duration:12s",
1711
            -- Check again because the soldier could have been expelled by the player
1712
            "checksoldier=soldier:attack level:3",
1713
            "consume=sword_long honey_bread,mead smoked_fish,smoked_meat",
1714
            "train=soldier:attack level:4"
1715
         }
1716
      },
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1717
*/
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1718
ProductionProgram::ActCheckSoldier::ActCheckSoldier(const std::vector<std::string>& arguments,
1719
                                                    const ProductionSiteDescr& descr) {
1720
	if (descr.type() != MapObjectType::TRAININGSITE) {
1721
		throw GameDataError("Illegal 'checksoldier' action in productionsite '%s'. This action is "
1722
		                    "only available to trainingsites.",
1723
		                    descr.name().c_str());
1724
	}
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1725
	if (arguments.size() != 2) {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1726
		throw GameDataError("Usage: checksoldier=soldier:attack|defense|evade|health level:<number>");
1727
	}
1728
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1729
	training_ = TrainingParameters(arguments, "checksoldier");
4677 by sigra
move more of the logic files into the logic directory
1730
}
1731
8048 by GunChleoc
Ran clang-format.
1732
void ProductionProgram::ActCheckSoldier::execute(Game& game, ProductionSite& ps) const {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1733
	assert(ps.descr().type() == MapObjectType::TRAININGSITE);
8382.2.2 by Holger Rapp
All done.
1734
	const SoldierControl* ctrl = ps.soldier_control();
8382.2.1 by Holger Rapp
Removed multiple inheritance for SoldierControl, but the interface still seems too fat.
1735
	assert(ctrl != nullptr);
1736
	const std::vector<Soldier*> soldiers = ctrl->present_soldiers();
9660 by The Widelands Bunnybot
Fix formatting action for branches on origin (#4500)
1737
1738
	upcast(TrainingSite, ts, &ps);
1739
6718.1.1 by charlyghislain at gmail
Skip when no soldier to train
1740
	if (soldiers.empty()) {
9660 by The Widelands Bunnybot
Fix formatting action for branches on origin (#4500)
1741
		ps.set_production_result(ts->descr().no_soldier_to_train_message());
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1742
		return ps.program_end(game, ProgramResult::kSkipped);
6718.1.1 by charlyghislain at gmail
Skip when no soldier to train
1743
	}
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1744
	ps.molog(game.get_gametime(), "  Checking soldier (%u) level %d)\n",
1745
	         static_cast<unsigned int>(training_.attribute), training_.level);
6718.1.1 by charlyghislain at gmail
Skip when no soldier to train
1746
8048 by GunChleoc
Ran clang-format.
1747
	const std::vector<Soldier*>::const_iterator soldiers_end = soldiers.end();
1748
	for (std::vector<Soldier*>::const_iterator it = soldiers.begin();; ++it) {
5540 by Nasenbaer
Fix bug #622888
1749
		if (it == soldiers_end) {
9660 by The Widelands Bunnybot
Fix formatting action for branches on origin (#4500)
1750
			ps.set_production_result(ts->descr().no_soldier_for_training_level_message());
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1751
			return ps.program_end(game, ProgramResult::kSkipped);
5540 by Nasenbaer
Fix bug #622888
1752
		}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1753
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1754
		if (training_.attribute == TrainingAttribute::kHealth) {
1755
			if ((*it)->get_health_level() == training_.level) {
1756
				break;
1757
			}
1758
		} else if (training_.attribute == TrainingAttribute::kAttack) {
1759
			if ((*it)->get_attack_level() == training_.level) {
1760
				break;
1761
			}
1762
		} else if (training_.attribute == TrainingAttribute::kDefense) {
1763
			if ((*it)->get_defense_level() == training_.level) {
1764
				break;
1765
			}
1766
		} else if (training_.attribute == TrainingAttribute::kEvade) {
1767
			if ((*it)->get_evade_level() == training_.level) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1768
				break;
1769
			}
4677 by sigra
move more of the logic files into the logic directory
1770
		}
1771
	}
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1772
	ps.molog(game.get_gametime(), "    okay\n");  // okay, do nothing
4677 by sigra
move more of the logic files into the logic directory
1773
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1774
	ts->training_attempted(training_.attribute, training_.level);
6560.1.1 by Teppo Maenpaa \
First version of standstill code; see forum topic 978 for descriptions, good for testing
1775
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1776
	ps.molog(game.get_gametime(), "  Check done!\n");
4677 by sigra
move more of the logic files into the logic directory
1777
1778
	return ps.program_step(game);
1779
}
1780
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1781
/* RST
1782
train
1783
-----
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1784
.. function:: train=soldier:attack|defense|evade|health level:\<number\>
1785
1786
   :arg string soldier: The soldier training attribute to be trained.
1787
1788
   :arg int level: The level that the soldier will receive for the given training attribute.
1789
9471 by The Widelands Bunnybot
Program documentation (#4140)
1790
.. note:: This action is only available to :ref:`training sites
1791
   <lua_tribes_buildings_trainingsites>`.
1792
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1793
Increases a soldier's training attribute to the given level. It is mandatory to call 'checksoldier'
1794
before calling this action to ensure that an appropriate soldier will be present at the site.
1795
Example:
1796
1797
.. code-block:: lua
1798
1799
      actions = {
1800
         "checksoldier=soldier:attack level:1",
1801
         "return=failed unless site has ax_broad",
1802
         "return=failed unless site has fish,meat",
1803
         "return=failed unless site has barbarians_bread",
1804
         "sleep=duration:30s",
1805
         -- This is called first to ensure that we have a matching soldier
1806
         "checksoldier=soldier:attack level:1",
1807
         "consume=ax_broad fish,meat barbarians_bread",
1808
         -- Now train the soldier's attack to level 2
1809
         "train=soldier:attack level:2"
1810
      }
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1811
*/
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1812
ProductionProgram::ActTrain::ActTrain(const std::vector<std::string>& arguments,
1813
                                      const ProductionSiteDescr& descr) {
1814
	if (descr.type() != MapObjectType::TRAININGSITE) {
1815
		throw GameDataError("Illegal 'train' action in productionsite '%s'. This action is "
1816
		                    "only available to trainingsites.",
1817
		                    descr.name().c_str());
1818
	}
1819
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1820
	if (arguments.size() != 2) {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1821
		throw GameDataError("Usage: train=soldier:attack|defense|evade|health level:<number>");
1822
	}
1823
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1824
	training_ = TrainingParameters(arguments, "train");
4677 by sigra
move more of the logic files into the logic directory
1825
}
1826
8048 by GunChleoc
Ran clang-format.
1827
void ProductionProgram::ActTrain::execute(Game& game, ProductionSite& ps) const {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1828
	assert(ps.descr().type() == MapObjectType::TRAININGSITE);
1829
	TrainingSite& ts = dynamic_cast<TrainingSite&>(ps);
8386 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/00_soldier_control:
1830
	const SoldierControl* ctrl = ps.soldier_control();
8382.2.2 by Holger Rapp
All done.
1831
	const std::vector<Soldier*> soldiers = ctrl->present_soldiers();
8048 by GunChleoc
Ran clang-format.
1832
	const std::vector<Soldier*>::const_iterator soldiers_end = soldiers.end();
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1833
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1834
	const unsigned current_level = ts.checked_soldier_training().level;
1835
	assert(current_level != INVALID_INDEX);
9640 by The Widelands Bunnybot
Shift asserts in ActTrain to get the log message first for debugging
1836
1837
	ps.molog(game.get_gametime(), "  Training soldier's %u (%d to %d)",
1838
	         static_cast<unsigned int>(training_.attribute), current_level, training_.level);
1839
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1840
	assert(current_level < training_.level);
1841
	assert(ts.checked_soldier_training().attribute == training_.attribute);
1842
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1843
	bool training_done = false;
1844
	for (auto it = soldiers.begin(); !training_done; ++it) {
5540 by Nasenbaer
Fix bug #622888
1845
		if (it == soldiers_end) {
7150.5.24 by fios at foramnagaidhlig
Changed ProductionSite char m_result_buffer[213] to private std::string m_production_result and added getter/setters
1846
			ps.set_production_result(_("No soldier found for this training level!"));
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
1847
			return ps.program_end(game, ProgramResult::kSkipped);
5540 by Nasenbaer
Fix bug #622888
1848
		}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1849
		try {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1850
			switch (training_.attribute) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1851
			case TrainingAttribute::kHealth:
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1852
				if ((*it)->get_health_level() == current_level) {
1853
					(*it)->set_health_level(training_.level);
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1854
					training_done = true;
1855
				}
1856
				break;
1857
			case TrainingAttribute::kAttack:
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1858
				if ((*it)->get_attack_level() == current_level) {
1859
					(*it)->set_attack_level(training_.level);
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1860
					training_done = true;
1861
				}
1862
				break;
1863
			case TrainingAttribute::kDefense:
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1864
				if ((*it)->get_defense_level() == current_level) {
1865
					(*it)->set_defense_level(training_.level);
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1866
					training_done = true;
1867
				}
1868
				break;
1869
			case TrainingAttribute::kEvade:
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1870
				if ((*it)->get_evade_level() == current_level) {
1871
					(*it)->set_evade_level(training_.level);
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1872
					training_done = true;
1873
				}
1874
				break;
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1875
			case TrainingAttribute::kTotal:
1876
				throw wexception("'total' training attribute can't be trained");
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1877
			}
1878
		} catch (...) {
1879
			throw wexception("Fail training soldier!!");
7839.9.3 by fios at foramnagaidhlig
Renamed all instances of "hp" and "hitpoints" to "health" for consistency. TrainingAttribute is now an enum class with consistent saveloading datatype.
1880
		}
4677 by sigra
move more of the logic files into the logic directory
1881
	}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1882
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1883
	ps.molog(game.get_gametime(), "  Training done!\n");
9089 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bugfix-buildings-tooltips:
1884
	ps.set_production_result(
9093 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/expedition_portspace_indicator:
1885
	   /** TRANSLATORS: Success message of a trainingsite '%s' stands for the description of the
1886
	    * training program, e.g. Completed upgrading soldier evade from level 0 to level 1 */
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1887
	   format(_("Completed %s"), ps.top_state().program->descname()));
4677 by sigra
move more of the logic files into the logic directory
1888
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
1889
	ts.training_successful(training_.attribute, current_level);
6560.1.1 by Teppo Maenpaa \
First version of standstill code; see forum topic 978 for descriptions, good for testing
1890
4677 by sigra
move more of the logic files into the logic directory
1891
	return ps.program_step(game);
1892
}
1893
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1894
/* RST
1895
playsound
1896
---------
9448 by The Widelands Bunnybot
Stop text input fields consuming some hotkeys (#4117)
1897
Plays a sound effect. See :ref:`map_object_programs_playsound`.
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1898
*/
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1899
ProductionProgram::ActPlaySound::ActPlaySound(const std::vector<std::string>& arguments)
1900
   : parameters(MapObjectProgram::parse_act_play_sound(arguments)) {
4677 by sigra
move more of the logic files into the logic directory
1901
}
1902
8048 by GunChleoc
Ran clang-format.
1903
void ProductionProgram::ActPlaySound::execute(Game& game, ProductionSite& ps) const {
9448 by The Widelands Bunnybot
Stop text input fields consuming some hotkeys (#4117)
1904
	Notifications::publish(NoteSound(SoundType::kAmbient, parameters.fx, ps.position_,
1905
	                                 parameters.priority, parameters.allow_multiple));
4677 by sigra
move more of the logic files into the logic directory
1906
	return ps.program_step(game);
1907
}
1908
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1909
/* RST
1910
construct
1911
---------
9445 by The Widelands Bunnybot
New syntax for productionsite construct program (#4118)
1912
.. function:: construct=\<immovable_name\> worker:\<program_name\> radius:\<number\>
1913
1914
   :arg string immovable_name: The name of the :ref:`immovable <lua_tribes_immovables>` to be
1915
      constructed, e.g. ``barbarians_shipconstruction``.
1916
1917
   :arg string worker: The :ref:`worker's program <tribes_worker_programs>` that makes the worker
1918
      walk to the immovable's location and do some work.
1919
1920
   :arg radius radius: The radius used by the worker to find a suitable construction spot on the
1921
      map.
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1922
1923
Sends the main worker to look for a suitable spot on the shore and to perform construction work on
9445 by The Widelands Bunnybot
New syntax for productionsite construct program (#4118)
1924
an immovable. Example:
1925
1926
.. code-block:: lua
1927
1928
      -- Production program actions
1929
      actions = {
1930
         "construct=barbarians_shipconstruction worker:buildship radius:6",
1931
         "sleep=duration:20s",
1932
      }
1933
1934
      -- Corresponding worker program
1935
      buildship = {
1936
         "walk=object-or-coords",
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1937
         "plant=attrib:barbarians_shipconstruction unless object",
9445 by The Widelands Bunnybot
New syntax for productionsite construct program (#4118)
1938
         "playsound=sound/sawmill/sawmill priority:80% allow_multiple",
1939
         "animate=work duration:500ms",
1940
         "construct",
1941
         "animate=work duration:5s",
1942
         "return"
1943
      },
9399 by The Widelands Bunnybot
Shift production program documentation to source code. (#4045)
1944
*/
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1945
ProductionProgram::ActConstruct::ActConstruct(const std::vector<std::string>& arguments,
8048 by GunChleoc
Ran clang-format.
1946
                                              const std::string& production_program_name,
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1947
                                              ProductionSiteDescr* descr,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1948
                                              const Descriptions& descriptions) {
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1949
	if (arguments.size() != 3) {
9445 by The Widelands Bunnybot
New syntax for productionsite construct program (#4118)
1950
		throw GameDataError(
1951
		   "Usage: construct=<immovable_name> worker:<program_name> radius:<number>");
1952
	}
1953
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
1954
	for (const std::string& argument : arguments) {
1955
		const std::pair<std::string, std::string> item = read_key_value_pair(argument, ':');
1956
		if (item.first == "worker") {
1957
			workerprogram = item.second;
1958
		} else if (item.first == "radius") {
1959
			radius = read_positive(item.second);
1960
		} else if (item.second.empty()) {
1961
			objectname = item.first;
1962
		} else {
1963
			throw GameDataError("Unknown parameter '%s'. Usage: construct=<immovable_name> "
1964
			                    "worker:<program_name> radius:<number>",
1965
			                    item.first.c_str());
9445 by The Widelands Bunnybot
New syntax for productionsite construct program (#4118)
1966
		}
1967
	}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
1968
1969
	const std::string description =
1970
	   descr->name() + ' ' + production_program_name + " construct " + objectname;
1971
	descr->workarea_info_[radius].insert(description);
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1972
1973
	// Register created immovable with productionsite
1974
	const WorkerDescr& main_worker_descr =
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1975
	   *descriptions.get_worker_descr(descr->working_positions().front().first);
9398 by The Widelands Bunnybot
Detect work area overlaps from MapObject programs (#4014)
1976
	for (const auto& attribute_info :
1977
	     main_worker_descr.get_program(workerprogram)->created_attributes()) {
1978
		descr->add_created_attribute(attribute_info);
1979
	}
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
1980
	descr->has_ship_fleet_check_ = true;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1981
}
1982
8048 by GunChleoc
Ran clang-format.
1983
const ImmovableDescr&
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1984
ProductionProgram::ActConstruct::get_construction_descr(const Descriptions& descriptions) const {
1985
	const ImmovableDescr* descr =
1986
	   descriptions.get_immovable_descr(descriptions.immovable_index(objectname));
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
1987
	if (descr == nullptr) {
5747 by Holger Rapp
Reverted revision 5744 as it broke automatic lua documentation creation
1988
		throw wexception("ActConstruct: immovable '%s' does not exist", objectname.c_str());
9369 by The Widelands Bunnybot
Add optional braces to tribes code (#3984)
1989
	}
5747 by Holger Rapp
Reverted revision 5744 as it broke automatic lua documentation creation
1990
1991
	return *descr;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1992
}
1993
8048 by GunChleoc
Ran clang-format.
1994
void ProductionProgram::ActConstruct::execute(Game& game, ProductionSite& psite) const {
1995
	ProductionSite::State& state = psite.top_state();
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
1996
	const ImmovableDescr& descr = get_construction_descr(game.descriptions());
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
1997
1998
	// Early check for no resources
8048 by GunChleoc
Ran clang-format.
1999
	const Buildcost& buildcost = descr.buildcost();
7617.2.1 by fios at foramnagaidhlig
Renamed WareIndex to DescriptionIndex.
2000
	DescriptionIndex available_resource = INVALID_INDEX;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2001
9580 by The Widelands Bunnybot
Modernize some loops (#4348)
2002
	for (const auto& item : buildcost) {
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
2003
		if (psite.inputqueue(item.first, wwWARE, nullptr).get_filled() > 0) {
9580 by The Widelands Bunnybot
Modernize some loops (#4348)
2004
			available_resource = item.first;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2005
			break;
2006
		}
5747 by Holger Rapp
Reverted revision 5744 as it broke automatic lua documentation creation
2007
	}
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2008
6952.1.2 by Holger Rapp
Finished fixing all uses of operator bool.
2009
	if (available_resource == INVALID_INDEX) {
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
2010
		psite.program_end(game, ProgramResult::kFailed);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2011
		return;
2012
	}
2013
2014
	// Look for an appropriate object in the given radius
8429.2.3 by GunChleoc
Further streamlined calls to egbase().map().
2015
	const Map& map = game.map();
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2016
	std::vector<ImmovableFound> immovables;
2017
	CheckStepWalkOn cstep(MOVECAPS_WALK, true);
9406 by The Widelands Bunnybot
Correct shipwright's work area (#4048)
2018
	Area<FCoords> area(map.get_fcoords(psite.get_position()), radius);
10752 by The Widelands Bunnybot
Further enhancements for ship construction (#6129)
2019
	FindImmovableAnd finder;
2020
	finder.add(FindImmovableByDescr(descr));
2021
	finder.add(FindImmovableNotReserved());
2022
	if (map.find_reachable_immovables(game, area, &immovables, cstep, finder) != 0U) {
10723 by The Widelands Bunnybot
Well-defined shipyards collaboration (#6070)
2023
		state.objvar = immovables.at(game.logic_rand() % immovables.size()).object;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2024
10050 by The Widelands Bunnybot
Intelligent worker reordering (#5099)
2025
		psite.working_positions_.at(psite.main_worker_)
2026
		   .worker.get(game)
2027
		   ->update_task_buildingwork(game);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2028
		return;
2029
	}
2030
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
2031
	std::vector<ShipFleetYardInterface*> candidates;
2032
	bool ships_needed = false;
2033
	for (ShipFleetYardInterface* interface : psite.get_ship_fleet_interfaces()) {
2034
		if (interface->get_fleet()->lacks_ship()) {
2035
			ships_needed = true;
2036
			BaseImmovable* immo = interface->get_position().field->get_immovable();
2037
			if (immo == nullptr || immo->get_size() == BaseImmovable::Size::NONE) {
2038
				candidates.push_back(interface);
2039
			}
2040
		}
2041
	}
2042
2043
	if (candidates.empty()) {
2044
		if (ships_needed || psite.get_ship_fleet_interfaces().empty()) {
2045
			psite.molog(game.get_gametime(), "construct: no space for ships\n");
2046
			psite.program_end(game, ProgramResult::kFailed);
2047
		} else {
2048
			psite.molog(game.get_gametime(), "construct: no ships needed\n");
2049
			psite.program_end(game, ProgramResult::kSkipped);
2050
		}
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2051
		return;
2052
	}
2053
10631 by The Widelands Bunnybot
Link ship/ferry yards to fleets and produce ships/ferries as needed (#5912)
2054
	state.coord = candidates.at(game.logic_rand() % candidates.size())->get_position();
2055
	psite.working_positions_.at(psite.main_worker_).worker.get(game)->update_task_buildingwork(game);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2056
}
2057
8048 by GunChleoc
Ran clang-format.
2058
bool ProductionProgram::ActConstruct::get_building_work(Game& game,
2059
                                                        ProductionSite& psite,
2060
                                                        Worker& worker) const {
2061
	ProductionSite::State& state = psite.top_state();
9038.1.10 by GunChleoc
Production program phases are now ProductionResults. This uncovered some suble bugs where ActSleep and ActAnimate would change the phase.
2062
	if (state.phase > ProgramResult::kNone) {
5614.1.5 by Nicolai Hähnle
Ship building works, but no saving yet
2063
		psite.program_step(game);
2064
		return false;
2065
	}
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2066
2067
	// First step: figure out which ware item to bring along
2068
	Buildcost remaining;
8048 by GunChleoc
Ran clang-format.
2069
	WaresQueue* wq = nullptr;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2070
8048 by GunChleoc
Ran clang-format.
2071
	Immovable* construction = dynamic_cast<Immovable*>(state.objvar.get(game));
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
2072
	if (construction != nullptr) {
10752 by The Widelands Bunnybot
Further enhancements for ship construction (#6129)
2073
		if (!construction->construct_remaining_buildcost(&remaining)) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2074
			psite.molog(game.get_gametime(), "construct: immovable %u not under construction",
2075
			            construction->serial());
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
2076
			psite.program_end(game, ProgramResult::kFailed);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2077
			return false;
2078
		}
2079
	} else {
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2080
		const ImmovableDescr& descr = get_construction_descr(game.descriptions());
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2081
		remaining = descr.buildcost();
2082
	}
2083
2084
	for (Buildcost::const_iterator it = remaining.begin(); it != remaining.end(); ++it) {
9636 by The Widelands Bunnybot
Implement percent notation for animation sound probability (#4423)
2085
		WaresQueue& thiswq = dynamic_cast<WaresQueue&>(psite.inputqueue(it->first, wwWARE, nullptr));
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2086
		if (thiswq.get_filled() > 0) {
2087
			wq = &thiswq;
2088
			break;
2089
		}
2090
	}
2091
10243 by The Widelands Bunnybot
Clear `readability-implicit-bool-conversion` in `logic` (#5310)
2092
	if (wq == nullptr) {
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
2093
		psite.program_end(game, ProgramResult::kFailed);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2094
		return false;
2095
	}
2096
6837 by Holger Rapp
Scratched an itch: item -> ware where appropriate.
2097
	// Second step: give ware to worker
6968.2.10 by Holger Rapp
Minor formatting issues.
2098
	WareInstance* ware =
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2099
	   new WareInstance(wq->get_index(), game.descriptions().get_ware_descr(wq->get_index()));
6837 by Holger Rapp
Scratched an itch: item -> ware where appropriate.
2100
	ware->init(game);
2101
	worker.set_carried_ware(game, ware);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2102
	wq->set_filled(wq->get_filled() - 1);
2103
2104
	// Third step: send worker on his merry way, giving the target object or coords
2105
	worker.start_task_program(game, workerprogram);
2106
	worker.top_state().objvar1 = construction;
2107
	worker.top_state().coords = state.coord;
10752 by The Widelands Bunnybot
Further enhancements for ship construction (#6129)
2108
	if (construction != nullptr) {
2109
		construction->set_reserved_by_worker(true);
2110
	}
5614.1.5 by Nicolai Hähnle
Ship building works, but no saving yet
2111
9038.1.10 by GunChleoc
Production program phases are now ProductionResults. This uncovered some suble bugs where ActSleep and ActAnimate would change the phase.
2112
	state.phase = ProgramResult::kFailed;
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2113
	return true;
2114
}
2115
8048 by GunChleoc
Ran clang-format.
2116
void ProductionProgram::ActConstruct::building_work_failed(Game& game,
2117
                                                           ProductionSite& psite,
10191 by The Widelands Bunnybot
Fix misc clang-tidy checks in `logic` (#5255)
2118
                                                           Worker& /* worker */) const {
9038.1.1 by GunChleoc
Fix shadow variable "None" in maphollowregion.h and ProgramResult.
2119
	psite.program_end(game, ProgramResult::kFailed);
5614.1.4 by Nicolai Hähnle
Initial cut of ship construction, untested, without proper savegame support
2120
}
2121
7810.1.1 by fios at foramnagaidhlig
Removed leading underscores from variable and function names.
2122
ProductionProgram::ProductionProgram(const std::string& init_name,
9492 by The Widelands Bunnybot
Get rid of duplicate translation fetching for tribes (#4170)
2123
                                     const LuaTable& program_table,
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2124
                                     Descriptions& descriptions,
8048 by GunChleoc
Ran clang-format.
2125
                                     ProductionSiteDescr* building)
9492 by The Widelands Bunnybot
Get rid of duplicate translation fetching for tribes (#4170)
2126
   : MapObjectProgram(init_name), descname_(program_table.get_string("descname")) {
2127
2128
	std::unique_ptr<LuaTable> actions_table = program_table.get_table("actions");
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2129
2130
	for (const std::string& line : actions_table->array_entries<std::string>()) {
2131
		if (line.empty()) {
2132
			throw GameDataError("Empty line");
2133
		}
2134
		try {
2135
			ProgramParseInput parseinput = parse_program_string(line);
2136
2137
			if (parseinput.name == "return") {
2138
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2139
				   new ActReturn(parseinput.arguments, *building, descriptions)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2140
			} else if (parseinput.name == "call") {
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
2141
				actions_.push_back(
2142
				   std::unique_ptr<ProductionProgram::Action>(new ActCall(parseinput.arguments)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2143
			} else if (parseinput.name == "sleep") {
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
2144
				actions_.push_back(
2145
				   std::unique_ptr<ProductionProgram::Action>(new ActSleep(parseinput.arguments)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2146
			} else if (parseinput.name == "animate") {
2147
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
2148
				   new ActAnimate(parseinput.arguments, building)));
2149
			} else if (parseinput.name == "consume") {
2150
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2151
				   new ActConsume(parseinput.arguments, *building, descriptions)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2152
			} else if (parseinput.name == "produce") {
2153
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2154
				   new ActProduce(parseinput.arguments, *building, descriptions)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2155
			} else if (parseinput.name == "recruit") {
2156
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2157
				   new ActRecruit(parseinput.arguments, *building, descriptions)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2158
			} else if (parseinput.name == "callworker") {
2159
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2160
				   new ActCallWorker(parseinput.arguments, name(), building, descriptions)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2161
			} else if (parseinput.name == "mine") {
2162
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2163
				   new ActMine(parseinput.arguments, descriptions, name(), building)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2164
			} else if (parseinput.name == "checksoldier") {
2165
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
2166
				   new ActCheckSoldier(parseinput.arguments, *building)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2167
			} else if (parseinput.name == "train") {
9465 by The Widelands Bunnybot
New API for trainingsite programs (#4126)
2168
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
2169
				   new ActTrain(parseinput.arguments, *building)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2170
			} else if (parseinput.name == "playsound") {
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
2171
				actions_.push_back(
2172
				   std::unique_ptr<ProductionProgram::Action>(new ActPlaySound(parseinput.arguments)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2173
			} else if (parseinput.name == "construct") {
2174
				actions_.push_back(std::unique_ptr<ProductionProgram::Action>(
9612 by The Widelands Bunnybot
Unify tribes world (#4240)
2175
				   new ActConstruct(parseinput.arguments, name(), building, descriptions)));
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2176
			} else {
2177
				throw GameDataError(
2178
				   "Unknown command '%s' in line '%s'", parseinput.name.c_str(), line.c_str());
2179
			}
2180
2181
			const ProductionProgram::Action& action = *actions_.back();
2182
			for (const auto& group : action.consumed_wares_workers()) {
2183
				consumed_wares_workers_.push_back(group);
2184
			}
2185
2186
			// Add produced wares. If the ware already exists, increase the amount
2187
			for (const auto& ware : action.produced_wares()) {
2188
				if (produced_wares_.count(ware.first) == 1) {
2189
					produced_wares_.at(ware.first) += ware.second;
2190
				} else {
2191
					produced_wares_.insert(ware);
2192
				}
2193
			}
2194
2195
			// Add recruited workers. If the worker already exists, increase the amount
2196
			for (const auto& worker : action.recruited_workers()) {
2197
				if (recruited_workers_.count(worker.first) == 1) {
2198
					recruited_workers_.at(worker.first) += worker.second;
2199
				} else {
2200
					recruited_workers_.insert(worker);
2201
				}
2202
			}
10449 by The Widelands Bunnybot
5589 traingsite encyclopedia (#5673)
2203
			// Add trained attributes
2204
			if (upcast(const ActCheckSoldier, act_cs, &action)) {
2205
				const auto& train = act_cs->training();
2206
				train_from_level_ = train.level;
2207
				if (train.attribute == Widelands::TrainingAttribute::kHealth) {
2208
					trained_attribute_ = "Health";
2209
				} else if (train.attribute == Widelands::TrainingAttribute::kAttack) {
2210
					trained_attribute_ = "Attack";
2211
				} else if (train.attribute == Widelands::TrainingAttribute::kDefense) {
2212
					trained_attribute_ = "Defense";
2213
				} else if (train.attribute == Widelands::TrainingAttribute::kEvade) {
2214
					trained_attribute_ = "Evade";
2215
				}
2216
			} else if (upcast(const ActTrain, act_tr, &action)) {
2217
				const auto& train = act_tr->training();
2218
				train_to_level_ = train.level;
2219
			}
9238 by The Widelands Bunnybot
Unify program parsers (#3805)
2220
		} catch (const std::exception& e) {
2221
			throw GameDataError("Error reading line '%s': %s", line.c_str(), e.what());
2222
		}
2223
	}
2224
2225
	if (actions_.empty()) {
2226
		throw GameDataError("No actions found");
2227
	}
2228
}
2229
8048 by GunChleoc
Ran clang-format.
2230
const std::string& ProductionProgram::descname() const {
2231
	return descname_;
2232
}
2233
size_t ProductionProgram::size() const {
2234
	return actions_.size();
2235
}
7175.14.9 by fios at foramnagaidhlig
Production program actouns are now stored in unique_ptr. Moved some implementation details from header to cc file.
2236
2237
const ProductionProgram::Action& ProductionProgram::operator[](size_t const idx) const {
8480.2.1 by GunChleoc
Fixed some warnings flagged up by clang-tidy:
2238
	return *actions_.at(idx);
7175.14.9 by fios at foramnagaidhlig
Production program actouns are now stored in unique_ptr. Moved some implementation details from header to cc file.
2239
}
2240
7175.17.53 by GunChleoc
Renamed consumed_wares to consumed_wares_workers. Tweaks to help strings.
2241
const ProductionProgram::Groups& ProductionProgram::consumed_wares_workers() const {
2242
	return consumed_wares_workers_;
8048 by GunChleoc
Ran clang-format.
2243
}
2244
const Buildcost& ProductionProgram::produced_wares() const {
2245
	return produced_wares_;
2246
}
2247
const Buildcost& ProductionProgram::recruited_workers() const {
2248
	return recruited_workers_;
2249
}
9451 by The Widelands Bunnybot
Rename main productionsite program to 'main' (#4119)
2250
2251
void ProductionProgram::validate_calls(const ProductionSiteDescr& descr) const {
2252
	for (const auto& action : actions_) {
2253
		if (upcast(const ActCall, act_call, action.get())) {
2254
			const std::string& program_name = act_call->program_name();
2255
			if (name() == program_name) {
2256
				throw GameDataError("Production program '%s' in %s is calling itself",
2257
				                    program_name.c_str(), descr.name().c_str());
2258
			}
2259
			const ProductionSiteDescr::Programs& programs = descr.programs();
2260
			ProductionSiteDescr::Programs::const_iterator const it = programs.find(program_name);
2261
			if (it == programs.end()) {
2262
				throw GameDataError("Trying to call unknown program '%s' in %s", program_name.c_str(),
2263
				                    descr.name().c_str());
2264
			}
2265
		}
2266
	}
2267
}
8048 by GunChleoc
Ran clang-format.
2268
}  // namespace Widelands