1 /*
2 * Copyright (C) 2006-2020 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "scripting/lua_bases.h"
21
22 #include <boost/algorithm/string.hpp>
23
24 #include "economy/economy.h"
25 #include "economy/road.h"
26 #include "economy/waterway.h"
27 #include "io/filesystem/layered_filesystem.h"
28 #include "io/profile.h"
29 #include "logic/filesystem_constants.h"
30 #include "logic/map_objects/checkstep.h"
31 #include "logic/map_objects/tribes/tribe_descr.h"
32 #include "logic/map_objects/tribes/tribes.h"
33 #include "logic/map_objects/tribes/ware_descr.h"
34 #include "logic/map_objects/world/world.h"
35 #include "logic/player.h"
36 #include "scripting/factory.h"
37 #include "scripting/globals.h"
38 #include "scripting/lua_map.h"
39 #include "ui_basic/progresswindow.h"
40
41 using namespace Widelands;
42
43 namespace LuaBases {
44
45 /* RST
46 :mod:`wl.bases`
47 ==================
48
49 .. module:: wl.bases
50 :synopsis: Base functions for common features in Game and Editor
51
52 .. moduleauthor:: The Widelands development team
53
54 .. currentmodule:: wl.bases
55
56 The :mod:`wl.bases` module contains Base functions on which the classes
57 of :mod:`wl.game` and :mod:`wl.editor` are based. You will not need
58 to create any of the functions in this module directly, but you might
59 use their functionality via the child classes.
60 */
61
62 /*
63 * ========================================================================
64 * MODULE CLASSES
65 * ========================================================================
66 */
67
68 /* RST
69 Module Classes
70 ^^^^^^^^^^^^^^^^
71
72 */
73
74 /* RST
75 EditorGameBase
76 --------------
77
78 .. class:: EditorGameBase
79
80 Common functionality between Editor and Game.
81 */
82
83 const char LuaEditorGameBase::className[] = "EditorGameBase";
84 const MethodType<LuaEditorGameBase> LuaEditorGameBase::Methods[] = {
85 METHOD(LuaEditorGameBase, get_immovable_description),
86 METHOD(LuaEditorGameBase, get_building_description),
87 METHOD(LuaEditorGameBase, get_tribe_description),
88 METHOD(LuaEditorGameBase, get_ware_description),
89 METHOD(LuaEditorGameBase, get_worker_description),
90 METHOD(LuaEditorGameBase, get_resource_description),
91 METHOD(LuaEditorGameBase, get_terrain_description),
92 METHOD(LuaEditorGameBase, save_campaign_data),
93 METHOD(LuaEditorGameBase, read_campaign_data),
94 METHOD(LuaEditorGameBase, set_loading_message),
95 {nullptr, nullptr},
96 };
97 const PropertyType<LuaEditorGameBase> LuaEditorGameBase::Properties[] = {
98 PROP_RO(LuaEditorGameBase, map),
99 PROP_RO(LuaEditorGameBase, players),
100 {nullptr, nullptr, nullptr},
101 };
102
__persist(lua_State *)103 void LuaEditorGameBase::__persist(lua_State* /* L */) {
104 }
__unpersist(lua_State *)105 void LuaEditorGameBase::__unpersist(lua_State* /* L */) {
106 }
107
108 /*
109 ==========================================================
110 PROPERTIES
111 ==========================================================
112 */
113 /* RST
114 .. attribute:: map
115
116 (RO) The :class:`~wl.map.Map` the game is played on.
117 */
get_map(lua_State * L)118 int LuaEditorGameBase::get_map(lua_State* L) {
119 to_lua<LuaMaps::LuaMap>(L, new LuaMaps::LuaMap());
120 return 1;
121 }
122
123 /* RST
124 .. attribute:: players
125
126 (RO) An :class:`array` with the defined players. The players are
127 either of type :class:`wl.game.Player` or :class:`wl.editor.Player`.
128
129 In game, there might be less players then defined in
130 :attr:`wl.map.Map.player_slots` because some slots might not be taken.
131 Also note that for the same reason you cannot index this array with
132 :attr:`wl.bases.PlayerBase.number`, but the players are ordered with
133 increasing number in this array.
134
135 The editor always creates all players that are defined by the map.
136 */
get_players(lua_State * L)137 int LuaEditorGameBase::get_players(lua_State* L) {
138 EditorGameBase& egbase = get_egbase(L);
139
140 lua_newtable(L);
141
142 uint32_t idx = 1;
143 for (PlayerNumber i = 1; i <= kMaxPlayers; i++) {
144 Player* rv = egbase.get_player(i);
145 if (!rv) {
146 continue;
147 }
148
149 lua_pushuint32(L, idx++);
150 get_factory(L).push_player(L, i);
151 lua_settable(L, -3);
152 }
153 return 1;
154 }
155
156 /*
157 ==========================================================
158 LUA METHODS
159 ==========================================================
160 */
161
162 /* RST
163 .. function:: get_immovable_description(immovable_name)
164
165 :arg immovable_name: the name of the immovable
166
167 Returns the ImmovableDescription for the named object.
168
169 (RO) The :class:`~wl.Game.Immovable_description`.
170 */
get_immovable_description(lua_State * L)171 int LuaEditorGameBase::get_immovable_description(lua_State* L) {
172 if (lua_gettop(L) != 2) {
173 report_error(L, "Wrong number of arguments");
174 }
175 const std::string immovable_name = luaL_checkstring(L, 2);
176 EditorGameBase& egbase = get_egbase(L);
177 const World& world = egbase.world();
178 DescriptionIndex idx = world.get_immovable_index(immovable_name);
179 if (idx != INVALID_INDEX) {
180 const ImmovableDescr* descr = world.get_immovable_descr(idx);
181 return to_lua<LuaMaps::LuaImmovableDescription>(
182 L, new LuaMaps::LuaImmovableDescription(descr));
183 }
184 const Tribes& tribes = egbase.tribes();
185 idx = tribes.immovable_index(immovable_name);
186 if (!tribes.immovable_exists(idx)) {
187 report_error(L, "Immovable %s does not exist", immovable_name.c_str());
188 }
189 const ImmovableDescr* descr = tribes.get_immovable_descr(idx);
190 return to_lua<LuaMaps::LuaImmovableDescription>(L, new LuaMaps::LuaImmovableDescription(descr));
191 }
192
193 /* RST
194 .. function:: get_building_description(building_description.name)
195
196 :arg building_name: the name of the building
197
198 Returns the description for the given building.
199
200 (RO) The :class:`~wl.Game.Building_description`.
201 */
get_building_description(lua_State * L)202 int LuaEditorGameBase::get_building_description(lua_State* L) {
203 if (lua_gettop(L) != 2) {
204 report_error(L, "Wrong number of arguments");
205 }
206 const Tribes& tribes = get_egbase(L).tribes();
207 const std::string building_name = luaL_checkstring(L, 2);
208 const DescriptionIndex building_index = tribes.building_index(building_name);
209 if (!tribes.building_exists(building_index)) {
210 report_error(L, "Building %s does not exist", building_name.c_str());
211 }
212 const BuildingDescr* building_description = tribes.get_building_descr(building_index);
213
214 return LuaMaps::upcasted_map_object_descr_to_lua(L, building_description);
215 }
216
217 /* RST
218 .. function:: get_tribe_description(tribe_name)
219
220 :arg tribe_name: the name of the tribe
221
222 Returns the tribe description of the given tribe.
223
224 (RO) The :class:`~wl.Game.Tribe_description`.
225 */
get_tribe_description(lua_State * L)226 int LuaEditorGameBase::get_tribe_description(lua_State* L) {
227 if (lua_gettop(L) != 2) {
228 report_error(L, "Wrong number of arguments");
229 }
230 EditorGameBase& egbase = get_egbase(L);
231 const std::string tribe_name = luaL_checkstring(L, 2);
232 if (!Widelands::tribe_exists(tribe_name)) {
233 report_error(L, "Tribe %s does not exist", tribe_name.c_str());
234 }
235 const TribeDescr* descr =
236 egbase.tribes().get_tribe_descr(egbase.tribes().tribe_index(tribe_name));
237 return to_lua<LuaMaps::LuaTribeDescription>(L, new LuaMaps::LuaTribeDescription(descr));
238 }
239
240 /* RST
241 .. function:: get_ware_description(ware_description.name)
242
243 :arg ware_name: the name of the ware
244
245 Returns the ware description for the given ware.
246
247 (RO) The :class:`~wl.Game.Ware_description`.
248 */
get_ware_description(lua_State * L)249 int LuaEditorGameBase::get_ware_description(lua_State* L) {
250 if (lua_gettop(L) != 2) {
251 report_error(L, "Wrong number of arguments");
252 }
253 const Tribes& tribes = get_egbase(L).tribes();
254 const std::string ware_name = luaL_checkstring(L, 2);
255 DescriptionIndex ware_index = tribes.ware_index(ware_name);
256 if (!tribes.ware_exists(ware_index)) {
257 report_error(L, "Ware %s does not exist", ware_name.c_str());
258 }
259 const WareDescr* ware_description = tribes.get_ware_descr(ware_index);
260 return LuaMaps::upcasted_map_object_descr_to_lua(L, ware_description);
261 }
262
263 /* RST
264 .. function:: get_worker_description(worker_description.name)
265
266 :arg worker_name: the name of the worker
267
268 Returs the worker desciption for the given worker.
269
270 (RO) The :class:`~wl.Game.Worker_description`.
271 */
get_worker_description(lua_State * L)272 int LuaEditorGameBase::get_worker_description(lua_State* L) {
273 if (lua_gettop(L) != 2) {
274 report_error(L, "Wrong number of arguments");
275 }
276 const Tribes& tribes = get_egbase(L).tribes();
277 const std::string worker_name = luaL_checkstring(L, 2);
278 const DescriptionIndex worker_index = tribes.worker_index(worker_name);
279 if (!tribes.worker_exists(worker_index)) {
280 report_error(L, "Worker %s does not exist", worker_name.c_str());
281 }
282 const WorkerDescr* worker_description = tribes.get_worker_descr(worker_index);
283 return LuaMaps::upcasted_map_object_descr_to_lua(L, worker_description);
284 }
285
286 /* RST
287 .. function:: get_resource_description(resource_name)
288
289 :arg resource_name: the name of the resource
290
291 Returns the resource description for the given resource.
292
293 (RO) The :class:`~wl.Game.Resource_description`.
294 */
get_resource_description(lua_State * L)295 int LuaEditorGameBase::get_resource_description(lua_State* L) {
296 if (lua_gettop(L) != 2) {
297 report_error(L, "Wrong number of arguments");
298 }
299 const std::string resource_name = luaL_checkstring(L, 2);
300 const World& world = get_egbase(L).world();
301 const DescriptionIndex idx = world.resource_index(resource_name.c_str());
302
303 if (idx == INVALID_INDEX) {
304 report_error(L, "Resource %s does not exist", resource_name.c_str());
305 }
306
307 const ResourceDescription* descr = world.get_resource(idx);
308 return to_lua<LuaMaps::LuaResourceDescription>(L, new LuaMaps::LuaResourceDescription(descr));
309 }
310
311 /* RST
312 .. function:: get_terrain_description(terrain_name)
313
314 :arg terrain_name: the name of the terrain
315
316 Returns a given terrain description for the given terrain.
317
318 (RO) The :class:`~wl.Game.Terrain_description`.
319 */
get_terrain_description(lua_State * L)320 int LuaEditorGameBase::get_terrain_description(lua_State* L) {
321 if (lua_gettop(L) != 2) {
322 report_error(L, "Wrong number of arguments");
323 }
324 const std::string terrain_name = luaL_checkstring(L, 2);
325 const TerrainDescription* descr = get_egbase(L).world().terrain_descr(terrain_name);
326 if (!descr) {
327 report_error(L, "Terrain %s does not exist", terrain_name.c_str());
328 }
329 return to_lua<LuaMaps::LuaTerrainDescription>(L, new LuaMaps::LuaTerrainDescription(descr));
330 }
331
332 /* Helper function for save_campaign_data()
333
334 This function reads the lua table from the stack and saves information about its
335 keys, values and data types and its size to the provided maps.
336 This function is recursive so subtables to any depth can be saved.
337 Each value in the table (including all subtables) is uniquely identified by a key_key.
338 The key_key is used as key in all the map.
339 For the topmost table of size x, the key_keys are called '_0' through '_x-1'.
340 For a subtable of size z at key_key '_y', the subtable's key_keys are called '_y_0' through
341 '_y_z-1'.
342 If a table is an array, the map 'keys' will contain no mappings for the array's key_keys.
343 */
save_table_recursively(lua_State * L,const std::string & depth,std::map<std::string,const char * > * data,std::map<std::string,const char * > * keys,std::map<std::string,const char * > * type,std::map<std::string,uint32_t> * size)344 static void save_table_recursively(lua_State* L,
345 const std::string& depth,
346 std::map<std::string, const char*>* data,
347 std::map<std::string, const char*>* keys,
348 std::map<std::string, const char*>* type,
349 std::map<std::string, uint32_t>* size) {
350 lua_pushnil(L);
351 uint32_t i = 0;
352 while (lua_next(L, -2) != 0) {
353 const std::string key_key = depth + "_" + std::to_string(i);
354
355 // check the value's type
356 const char* type_name = lua_typename(L, lua_type(L, -1));
357 const std::string t = std::string(type_name);
358
359 (*type)[key_key] = type_name;
360
361 if (t == "number" || t == "string") {
362 // numbers may be treated like strings here
363 (*data)[key_key] = luaL_checkstring(L, -1);
364 } else if (t == "boolean") {
365 (*data)[key_key] = luaL_checkboolean(L, -1) ? "true" : "false";
366 } else if (t == "table") {
367 save_table_recursively(L, depth + "_" + std::to_string(i), data, keys, type, size);
368 } else {
369 report_error(
370 L, "A campaign data value may be a string, integer, boolean, or table; but not a %s!",
371 type_name);
372 }
373
374 ++i;
375
376 // put the key on the stack top
377 lua_pop(L, 1);
378 if (lua_type(L, -1) == LUA_TSTRING) {
379 // this is a table
380 (*keys)[key_key] = luaL_checkstring(L, -1);
381 } else if (lua_type(L, -1) == LUA_TNUMBER) {
382 // this is an array
383 if (i != luaL_checkuint32(L, -1)) {
384 // If we get here, the scripter must have set some array values to nil.
385 // This is forbidden because it causes problems when trying to read the data later.
386 report_error(L, "A campaign data array entry must not be nil!");
387 }
388 // otherwise, this is a normal array, so all is well
389 } else {
390 report_error(L, "A campaign data key may be a string or integer; but not a %s!",
391 lua_typename(L, lua_type(L, -1)));
392 }
393 }
394 (*size)[depth] = i;
395 }
396
397 /* RST
398 .. function:: save_campaign_data(campaign_name, scenario_name, data)
399
400 :arg campaign_name: the name of the current campaign, e.g. "empiretut" or "frisians"
401 :arg scenario_name: the name of the current scenario, e.g. "emp04" or "fri03"
402 :arg data: a table of key-value pairs to save
403
404 Saves information that can be read by other scenarios.
405
406 If an array is used, the data will be saved in the correct order. Arrays may not contain nil
407 values. If the table is not an array, all keys have to be strings. Tables may contain
408 subtables of any depth. Cyclic dependencies will cause Widelands to crash. Only tables/arrays,
409 strings, integer numbers and booleans may be used as values.
410 */
save_campaign_data(lua_State * L)411 int LuaEditorGameBase::save_campaign_data(lua_State* L) {
412
413 const std::string campaign_name = luaL_checkstring(L, 2);
414 const std::string scenario_name = luaL_checkstring(L, 3);
415 luaL_checktype(L, 4, LUA_TTABLE);
416
417 std::string dir = kCampaignDataDir + g_fs->file_separator() + campaign_name;
418 boost::trim(dir);
419 g_fs->ensure_directory_exists(dir);
420
421 std::string complete_filename =
422 dir + g_fs->file_separator() + scenario_name + kCampaignDataExtension;
423 boost::trim(complete_filename);
424
425 std::map<std::string, const char*> data;
426 std::map<std::string, const char*> keys;
427 std::map<std::string, const char*> type;
428 std::map<std::string, uint32_t> size;
429
430 save_table_recursively(L, "", &data, &keys, &type, &size);
431
432 Profile profile;
433 Section& data_section = profile.create_section("data");
434 for (const auto& p : data) {
435 data_section.set_string(p.first.c_str(), p.second);
436 }
437 Section& keys_section = profile.create_section("keys");
438 for (const auto& p : keys) {
439 keys_section.set_string(p.first.c_str(), p.second);
440 }
441 Section& type_section = profile.create_section("type");
442 for (const auto& p : type) {
443 type_section.set_string(p.first.c_str(), p.second);
444 }
445 Section& size_section = profile.create_section("size");
446 for (const auto& p : size) {
447 size_section.set_natural(p.first.c_str(), p.second);
448 }
449
450 profile.write(complete_filename.c_str(), false);
451
452 return 0;
453 }
454
455 /* Helper function for read_campaign_data()
456
457 This function reads the campaign data file and re-creates the table the data was created from.
458 This function is recursive so subtables to any depth can be created.
459 For information on section structure and key_keys, see the comment for save_table_recursively().
460 This function first newly creates the table to write data to, and the number of items in the
461 table is read.
462 For each item, the unique key_key is created. If the 'keys' section doesn't contain an entry for
463 that key_key,
464 it must be because this table is supposed to be an array. Then the data type is checked
465 and the key-value pair is written to the table as the correct type.
466 */
push_table_recursively(lua_State * L,const std::string & depth,Section * data_section,Section * keys_section,Section * type_section,Section * size_section)467 static void push_table_recursively(lua_State* L,
468 const std::string& depth,
469 Section* data_section,
470 Section* keys_section,
471 Section* type_section,
472 Section* size_section) {
473 const uint32_t size = size_section->get_natural(depth.c_str());
474 lua_newtable(L);
475 for (uint32_t i = 0; i < size; i++) {
476 const std::string key_key_str(depth + '_' + std::to_string(i));
477 const char* key_key = key_key_str.c_str();
478 if (keys_section->has_val(key_key)) {
479 // This is a table
480 lua_pushstring(L, keys_section->get_string(key_key));
481 } else {
482 // This must be an array
483 lua_pushinteger(L, i + 1);
484 }
485
486 // check the data type and push the value
487 const std::string type = type_section->get_string(key_key);
488
489 if (type == "boolean") {
490 lua_pushboolean(L, data_section->get_bool(key_key));
491 } else if (type == "number") {
492 lua_pushinteger(L, data_section->get_int(key_key));
493 } else if (type == "string") {
494 lua_pushstring(L, data_section->get_string(key_key));
495 } else if (type == "table") {
496 // creates a new (sub-)table at the stacktop, populated with its own key-value-pairs
497 push_table_recursively(L, depth + "_" + std::to_string(i), data_section, keys_section,
498 type_section, size_section);
499 } else {
500 // this code should not be reached unless the user manually edited the .wcd file
501 log("Illegal data type %s in campaign data file, setting key %s to nil\n", type.c_str(),
502 luaL_checkstring(L, -1));
503 lua_pushnil(L);
504 }
505 lua_settable(L, -3);
506 }
507 }
508
509 /* RST
510 .. function:: read_campaign_data(campaign_name, scenario_name)
511
512 :arg campaign_name: the name of the campaign, e.g. "empiretut" or "frisians"
513 :arg scenario_name: the name of the scenario that saved the data, e.g. "emp04" or "fri03"
514
515 Reads information that was saved by another scenario.
516 The data is returned as a table of key-value pairs.
517 The table is not guaranteed to be in any particular order, unless it is an array,
518 in which case it will be returned in the same order as it was saved.
519 This function returns :const:`nil` if the file cannot be opened for reading.
520 */
read_campaign_data(lua_State * L)521 int LuaEditorGameBase::read_campaign_data(lua_State* L) {
522 const std::string campaign_name = luaL_checkstring(L, 2);
523 const std::string scenario_name = luaL_checkstring(L, 3);
524
525 std::string complete_filename = kCampaignDataDir + g_fs->file_separator() + campaign_name +
526 g_fs->file_separator() + scenario_name + kCampaignDataExtension;
527 boost::trim(complete_filename);
528
529 Profile profile;
530 profile.read(complete_filename.c_str());
531 Section* data_section = profile.get_section("data");
532 Section* keys_section = profile.get_section("keys");
533 Section* type_section = profile.get_section("type");
534 Section* size_section = profile.get_section("size");
535 if (data_section == nullptr || keys_section == nullptr || type_section == nullptr ||
536 size_section == nullptr) {
537 log("Unable to read campaign data file, returning nil\n");
538 lua_pushnil(L);
539 } else {
540 push_table_recursively(L, "", data_section, keys_section, type_section, size_section);
541 }
542
543 return 1;
544 }
545
546 /* RST
547 .. function:: set_loading_message(text)
548
549 :arg text: the text to display
550
551 Change the progress message on the loading screen.
552 May be used from the init.lua files for tribe/world loading only.
553 */
set_loading_message(lua_State * L)554 int LuaEditorGameBase::set_loading_message(lua_State* L) {
555 get_egbase(L).step_loader_ui(luaL_checkstring(L, 2));
556 return 0;
557 }
558
559 /*
560 ==========================================================
561 C METHODS
562 ==========================================================
563 */
564
565 /* RST
566 PlayerBase
567 ----------
568
569 .. class:: PlayerBase
570
571 The Base class for the Player objects in Editor and Game
572 */
573
574 const char LuaPlayerBase::className[] = "PlayerBase";
575 const MethodType<LuaPlayerBase> LuaPlayerBase::Methods[] = {
576 METHOD(LuaPlayerBase, __eq), METHOD(LuaPlayerBase, __tostring),
577 METHOD(LuaPlayerBase, conquer), METHOD(LuaPlayerBase, get_wares),
578 METHOD(LuaPlayerBase, get_workers), METHOD(LuaPlayerBase, place_building),
579 METHOD(LuaPlayerBase, place_flag), METHOD(LuaPlayerBase, place_road),
580 METHOD(LuaPlayerBase, place_ship), {nullptr, nullptr},
581 };
582 const PropertyType<LuaPlayerBase> LuaPlayerBase::Properties[] = {
583 PROP_RO(LuaPlayerBase, number), PROP_RO(LuaPlayerBase, tribe_name), {nullptr, nullptr, nullptr},
584 };
585
__persist(lua_State * L)586 void LuaPlayerBase::__persist(lua_State* L) {
587 PERS_UINT32("player", player_number_);
588 }
__unpersist(lua_State * L)589 void LuaPlayerBase::__unpersist(lua_State* L) {
590 UNPERS_UINT32("player", player_number_)
591 }
592
593 /*
594 ==========================================================
595 PROPERTIES
596 ==========================================================
597 */
598 /* RST
599 .. attribute:: number
600
601 (RO) The number of this Player.
602 */
get_number(lua_State * L)603 int LuaPlayerBase::get_number(lua_State* L) {
604 lua_pushuint32(L, player_number_);
605 return 1;
606 }
607
608 /* RST
609 .. attribute:: tribe_name
610
611 (RO) The name of the tribe of this player.
612 */
get_tribe_name(lua_State * L)613 int LuaPlayerBase::get_tribe_name(lua_State* L) {
614 lua_pushstring(L, get(L, get_egbase(L)).tribe().name());
615 return 1;
616 }
617
618 /*
619 ==========================================================
620 LUA METHODS
621 ==========================================================
622 */
__eq(lua_State * L)623 int LuaPlayerBase::__eq(lua_State* L) {
624 EditorGameBase& egbase = get_egbase(L);
625 const Player& me = get(L, egbase);
626 const Player& you = (*get_base_user_class<LuaPlayerBase>(L, 2))->get(L, egbase);
627
628 lua_pushboolean(L, (me.player_number() == you.player_number()));
629 return 1;
630 }
631
__tostring(lua_State * L)632 int LuaPlayerBase::__tostring(lua_State* L) {
633 const std::string pushme = (boost::format("Player(%i)") %
634 static_cast<unsigned int>(get(L, get_egbase(L)).player_number()))
635 .str();
636 lua_pushstring(L, pushme.c_str());
637 return 1;
638 }
639 /* RST
640 .. function:: place_flag(field[, force])
641
642 Builds a flag on a given field if it is legal to do so. If not,
643 reports an error
644
645 :arg field: where the flag should be created
646 :type field: :class:`wl.map.Field`
647 :arg force: If this is :const:`true` then the map is created with
648 pure force:
649
650 * if there is an immovable on this field, it will be
651 removed
652 * if there are flags too close by to this field, they will be
653 ripped
654 * if the player does not own the territory, it is conquered
655 for him.
656 :type force: :class:`boolean`
657 :returns: :class:`wl.map.Flag` object created or :const:`nil`.
658 */
place_flag(lua_State * L)659 int LuaPlayerBase::place_flag(lua_State* L) {
660 uint32_t n = lua_gettop(L);
661 LuaMaps::LuaField* c = *get_user_class<LuaMaps::LuaField>(L, 2);
662 bool force = false;
663 if (n > 2) {
664 force = luaL_checkboolean(L, 3);
665 }
666
667 Flag* f;
668 if (!force) {
669 f = get(L, get_egbase(L)).build_flag(c->fcoords(L));
670 if (!f) {
671 report_error(L, "Couldn't build flag!");
672 }
673 } else {
674 f = &get(L, get_egbase(L)).force_flag(c->fcoords(L));
675 }
676
677 return to_lua<LuaMaps::LuaFlag>(L, new LuaMaps::LuaFlag(*f));
678 }
679
680 /* RST
681 .. method:: place_road(roadtype, f1, dir1, dir2, ...[, force=false])
682
683 Start a road or waterway at the given field, then walk the directions
684 given. Places a flag at the last field.
685
686 If the last argument to this function is :const:`true` the road will
687 be created by force: all immovables in the way are removed and land
688 is conquered.
689
690 :arg roadtype: 'normal', 'busy', or 'waterway'
691 :type roadtype: :class:`string`
692 :arg f1: fields to connect with this road
693 :type f1: :class:`wl.map.Field`
694 :arg dirs: direction, can be either ("r", "l", "br", "bl", "tr", "tl") or
695 ("e", "w", "ne", "nw", "se", "sw").
696 :type dirs: :class:`string`
697
698 :returns: the road created
699 */
place_road(lua_State * L)700 int LuaPlayerBase::place_road(lua_State* L) {
701 EditorGameBase& egbase = get_egbase(L);
702 const Map& map = egbase.map();
703
704 const std::string roadtype = luaL_checkstring(L, 2);
705 Flag* starting_flag = (*get_user_class<LuaMaps::LuaFlag>(L, 3))->get(L, egbase);
706 Coords current = starting_flag->get_position();
707 Path path(current);
708
709 bool force_road = false;
710 if (lua_isboolean(L, -1)) {
711 force_road = luaL_checkboolean(L, -1);
712 lua_pop(L, 1);
713 }
714
715 // Construct the path
716 CheckStepLimited cstep;
717 for (int32_t i = 4; i <= lua_gettop(L); i++) {
718 std::string d = luaL_checkstring(L, i);
719
720 if (d == "ne" || d == "tr") {
721 path.append(map, 1);
722 map.get_trn(current, ¤t);
723 } else if (d == "e" || d == "r") {
724 path.append(map, 2);
725 map.get_rn(current, ¤t);
726 } else if (d == "se" || d == "br") {
727 path.append(map, 3);
728 map.get_brn(current, ¤t);
729 } else if (d == "sw" || d == "bl") {
730 path.append(map, 4);
731 map.get_bln(current, ¤t);
732 } else if (d == "w" || d == "l") {
733 path.append(map, 5);
734 map.get_ln(current, ¤t);
735 } else if (d == "nw" || d == "tl") {
736 path.append(map, 6);
737 map.get_tln(current, ¤t);
738 } else {
739 report_error(L, "Illegal direction: %s", d.c_str());
740 }
741
742 cstep.add_allowed_location(current);
743 }
744
745 // Make sure that the road cannot cross itself
746 Path optimal_path;
747 map.findpath(path.get_start(), path.get_end(), 0, optimal_path, cstep, Map::fpBidiCost);
748 if (optimal_path.get_nsteps() != path.get_nsteps()) {
749 report_error(L, "Cannot build a road that crosses itself!");
750 }
751
752 RoadBase* r = nullptr;
753 if (force_road) {
754 if (roadtype == "waterway") {
755 r = &get(L, egbase).force_waterway(path);
756 } else {
757 Road& road = get(L, egbase).force_road(path);
758 if (roadtype == "busy") {
759 road.set_busy(egbase, true);
760 } else if (roadtype != "normal") {
761 report_error(
762 L, "Invalid road type '%s' (permitted values are 'normal', 'busy', and 'waterway'",
763 roadtype.c_str());
764 }
765 r = &road;
766 }
767 } else {
768 BaseImmovable* bi = map.get_immovable(current);
769 if (!bi || bi->descr().type() != MapObjectType::FLAG) {
770 if (!get(L, egbase).build_flag(current)) {
771 report_error(L, "Could not place end flag!");
772 }
773 }
774 if (bi && bi == starting_flag) {
775 report_error(L, "Cannot build a closed loop!");
776 }
777
778 if (roadtype == "waterway") {
779 r = get(L, egbase).build_waterway(path);
780 } else {
781 Road* road = get(L, egbase).build_road(path);
782 if (roadtype == "busy") {
783 if (road) {
784 road->set_busy(egbase, true);
785 }
786 } else if (roadtype != "normal") {
787 report_error(
788 L, "Invalid road type '%s' (permitted values are 'normal', 'busy', and 'waterway'",
789 roadtype.c_str());
790 }
791 r = road;
792 }
793 }
794
795 if (!r) {
796 report_error(L, "Error while creating Road. May be: something is in "
797 "the way or you do not own the territory where you want to build "
798 "the road");
799 }
800
801 return to_lua<LuaMaps::LuaRoad>(L, new LuaMaps::LuaRoad(*r));
802 }
803
804 /* RST
805 .. method:: place_building(name, field[, cs = false, force = false])
806
807 Immediately creates a building on the given field. The building starts
808 out completely empty. If :const:`cs` is set, the building
809 is not created directly, instead a constructionsite for this building is
810 placed.
811
812 If the :const:`force` argument is set, the building is forced into
813 existence: the same action is taken as for :meth:`place_flag` when force
814 is :const:`true`. Additionally, all buildings that are too close to the
815 new one are ripped.
816
817 :returns: a subclass of :class:`wl.map.Building`
818 */
place_building(lua_State * L)819 int LuaPlayerBase::place_building(lua_State* L) {
820 const std::string& name = luaL_checkstring(L, 2);
821 LuaMaps::LuaField* c = *get_user_class<LuaMaps::LuaField>(L, 3);
822 bool constructionsite = false;
823 bool force = false;
824
825 if (lua_gettop(L) >= 4) {
826 constructionsite = luaL_checkboolean(L, 4);
827 }
828 if (lua_gettop(L) >= 5) {
829 force = luaL_checkboolean(L, 5);
830 }
831
832 EditorGameBase& egbase = get_egbase(L);
833 const Tribes& tribes = egbase.tribes();
834
835 if (!tribes.building_exists(name)) {
836 report_error(L, "Unknown Building: '%s'", name.c_str());
837 }
838 DescriptionIndex building_index = tribes.building_index(name);
839
840 FormerBuildings former_buildings;
841 find_former_buildings(tribes, building_index, &former_buildings);
842 if (constructionsite) {
843 former_buildings.pop_back();
844 }
845
846 Building* b = nullptr;
847 if (force) {
848 if (constructionsite) {
849 b = &get(L, egbase).force_csite(c->coords(), building_index, former_buildings);
850 } else {
851 b = &get(L, egbase).force_building(c->coords(), former_buildings);
852 }
853 } else {
854 b = get(L, egbase).build(c->coords(), building_index, constructionsite, former_buildings);
855 }
856 if (!b) {
857 report_error(L, "Couldn't place building!");
858 }
859
860 LuaMaps::upcasted_map_object_to_lua(L, b);
861 return 1;
862 }
863
864 /* RST
865 .. method:: place_ship(field)
866
867 Places a ship for the player's tribe, which will be
868 owned by the player.
869
870 :arg field: where the ship should be placed.
871 :type field: :class:`wl.map.Field`
872
873 :returns: The new ship that was created.
874 */
875 // UNTESTED
place_ship(lua_State * L)876 int LuaPlayerBase::place_ship(lua_State* L) {
877 LuaMaps::LuaField* c = *get_user_class<LuaMaps::LuaField>(L, 2);
878
879 EditorGameBase& egbase = get_egbase(L);
880 Player& player = get(L, egbase);
881
882 const ShipDescr* descr = egbase.tribes().get_ship_descr(player.tribe().ship());
883 Bob& ship = egbase.create_ship(c->coords(), descr->name(), &player);
884
885 LuaMaps::upcasted_map_object_to_lua(L, &ship);
886
887 return 1;
888 }
889
890 /* RST
891 .. method:: conquer(f[, radius=1])
892
893 Conquer this area around the given field if it does not belong to the
894 player already. This will conquer the fields no matter who owns it at the
895 moment.
896
897 :arg f: center field for conquering
898 :type f: :class:`wl.map.Field`
899 :arg radius: radius to conquer around. Default value makes this call
900 conquer 7 fields
901 :type radius: :class:`integer`
902 :returns: :const:`nil`
903 */
conquer(lua_State * L)904 int LuaPlayerBase::conquer(lua_State* L) {
905 uint32_t radius = 1;
906 if (lua_gettop(L) > 2) {
907 radius = luaL_checkuint32(L, 3);
908 }
909
910 get_egbase(L).conquer_area_no_building(PlayerArea<Area<FCoords>>(
911 player_number_,
912 Area<FCoords>((*get_user_class<LuaMaps::LuaField>(L, 2))->fcoords(L), radius)));
913 return 0;
914 }
915
916 /* RST
917 .. method:: get_workers(name)
918
919 Returns the number of workers of this type in the players stock. This does not implement
920 everything that :class:`HasWorkers` offers.
921
922 :arg name: name of the worker to get
923 :type name: :class:`string`.
924 :returns: the number of workers
925 */
926 // UNTESTED
get_workers(lua_State * L)927 int LuaPlayerBase::get_workers(lua_State* L) {
928 Player& player = get(L, get_egbase(L));
929 const std::string workername = luaL_checkstring(L, -1);
930
931 const DescriptionIndex worker = player.tribe().worker_index(workername);
932
933 uint32_t nworkers = 0;
934 for (const auto& economy : player.economies()) {
935 if (economy.second->type() == Widelands::wwWORKER) {
936 nworkers += economy.second->stock_ware_or_worker(worker);
937 }
938 }
939 lua_pushuint32(L, nworkers);
940 return 1;
941 }
942
943 /* RST
944 .. method:: get_wares(name)
945
946 Returns the number of wares of this type in the players stock. This does not implement
947 everything that :class:`HasWorkers` offers.
948
949 :arg name: name of the worker to get
950 :type name: :class:`string`.
951 :returns: the number of wares
952 */
953 // UNTESTED
get_wares(lua_State * L)954 int LuaPlayerBase::get_wares(lua_State* L) {
955 EditorGameBase& egbase = get_egbase(L);
956 Player& player = get(L, egbase);
957 const std::string warename = luaL_checkstring(L, -1);
958
959 const DescriptionIndex ware = egbase.tribes().ware_index(warename);
960
961 uint32_t nwares = 0;
962 for (const auto& economy : player.economies()) {
963 if (economy.second->type() == Widelands::wwWARE) {
964 nwares += economy.second->stock_ware_or_worker(ware);
965 }
966 }
967 lua_pushuint32(L, nwares);
968 return 1;
969 }
970
971 /*
972 ==========================================================
973 C METHODS
974 ==========================================================
975 */
get(lua_State * L,Widelands::EditorGameBase & egbase)976 Player& LuaPlayerBase::get(lua_State* L, Widelands::EditorGameBase& egbase) {
977 if (player_number_ > kMaxPlayers) {
978 report_error(L, "Illegal player number %i", player_number_);
979 }
980 Player* rv = egbase.get_player(player_number_);
981 if (!rv) {
982 report_error(L, "Player with the number %i does not exist", player_number_);
983 }
984 return *rv;
985 }
986
987 /*
988 * ========================================================================
989 * MODULE FUNCTIONS
990 * ========================================================================
991 */
992
993 const static struct luaL_Reg wlbases[] = {{nullptr, nullptr}};
994
luaopen_wlbases(lua_State * const L)995 void luaopen_wlbases(lua_State* const L) {
996 lua_getglobal(L, "wl"); // S: wl_table
997 lua_pushstring(L, "bases"); // S: wl_table "bases"
998 luaL_newlib(L, wlbases); // S: wl_table "bases" wl.bases_table
999 lua_settable(L, -3); // S: wl_table
1000 lua_pop(L, 1); // S:
1001
1002 register_class<LuaEditorGameBase>(L, "bases");
1003 register_class<LuaPlayerBase>(L, "bases");
1004 }
1005 } // namespace LuaBases
1006