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_game.h"
21
22 #include <memory>
23
24 #include "economy/economy.h"
25 #include "economy/flag.h"
26 #include "logic/filesystem_constants.h"
27 #include "logic/game_controller.h"
28 #include "logic/map_objects/tribes/tribe_descr.h"
29 #include "logic/message.h"
30 #include "logic/objective.h"
31 #include "logic/path.h"
32 #include "logic/player.h"
33 #include "logic/player_end_result.h"
34 #include "logic/playersmanager.h"
35 #include "scripting/globals.h"
36 #include "scripting/lua_map.h"
37 #include "wlapplication_options.h"
38 #include "wui/interactive_player.h"
39 #include "wui/story_message_box.h"
40
41 using namespace Widelands;
42 using namespace LuaMaps;
43
44 namespace LuaGame {
45
46 /* RST
47 :mod:`wl.game`
48 ======================
49
50 .. module:: wl.game
51 :synopsis: Provides access on game internals like Players
52
53 .. moduleauthor:: The Widelands development team
54
55 .. currentmodule:: wl.game
56 */
57
58 /*
59 * ========================================================================
60 * MODULE CLASSES
61 * ========================================================================
62 */
63
64 /* RST
65 Module Classes
66 ^^^^^^^^^^^^^^^^
67
68 */
69
70 /* RST
71 Player
72 ------
73
74 .. class:: Player
75
76 Child of: :class:`wl.bases.PlayerBase`
77
78 This class represents one of the players in the game. You can access
79 information about this player or act on his behalf. Note that you cannot
80 instantiate a class of this type directly, use the :attr:`wl.Game.players`
81 insteadl
82 */
83 const char LuaPlayer::className[] = "Player";
84 const MethodType<LuaPlayer> LuaPlayer::Methods[] = {
85 METHOD(LuaPlayer, send_message),
86 METHOD(LuaPlayer, message_box),
87 METHOD(LuaPlayer, sees_field),
88 METHOD(LuaPlayer, seen_field),
89 METHOD(LuaPlayer, allow_buildings),
90 METHOD(LuaPlayer, forbid_buildings),
91 METHOD(LuaPlayer, add_objective),
92 METHOD(LuaPlayer, reveal_fields),
93 METHOD(LuaPlayer, hide_fields),
94 METHOD(LuaPlayer, reveal_scenario),
95 METHOD(LuaPlayer, reveal_campaign),
96 METHOD(LuaPlayer, mark_scenario_as_solved),
97 METHOD(LuaPlayer, get_ships),
98 METHOD(LuaPlayer, get_buildings),
99 METHOD(LuaPlayer, get_suitability),
100 METHOD(LuaPlayer, allow_workers),
101 METHOD(LuaPlayer, switchplayer),
102 METHOD(LuaPlayer, get_produced_wares_count),
103 METHOD(LuaPlayer, set_attack_forbidden),
104 METHOD(LuaPlayer, is_attack_forbidden),
105 {nullptr, nullptr},
106 };
107 const PropertyType<LuaPlayer> LuaPlayer::Properties[] = {
108 PROP_RO(LuaPlayer, name), PROP_RO(LuaPlayer, allowed_buildings),
109 PROP_RO(LuaPlayer, objectives), PROP_RO(LuaPlayer, defeated),
110 PROP_RO(LuaPlayer, messages), PROP_RO(LuaPlayer, inbox),
111 PROP_RO(LuaPlayer, color), PROP_RW(LuaPlayer, team),
112 PROP_RO(LuaPlayer, tribe), PROP_RW(LuaPlayer, see_all),
113 {nullptr, nullptr, nullptr},
114 };
115
116 /*
117 ==========================================================
118 PROPERTIES
119 ==========================================================
120 */
121 /* RST
122 .. attribute:: name
123
124 (RO) The name of this Player.
125 */
get_name(lua_State * L)126 int LuaPlayer::get_name(lua_State* L) {
127 Game& game = get_game(L);
128 Player& p = get(L, game);
129 lua_pushstring(L, p.get_name());
130 return 1;
131 }
132
133 /* RST
134 .. attribute:: allowed_buildings
135
136 (RO) an array with name:bool values with all buildings
137 that are currently allowed for this player. Note that
138 you can not enable/forbid a building by setting the value. Use
139 :meth:`allow_buildings` or :meth:`forbid_buildings` for that.
140 */
get_allowed_buildings(lua_State * L)141 int LuaPlayer::get_allowed_buildings(lua_State* L) {
142 EditorGameBase& egbase = get_egbase(L);
143 Player& player = get(L, egbase);
144
145 lua_newtable(L);
146 for (DescriptionIndex i = 0; i < egbase.tribes().nrbuildings(); ++i) {
147 const BuildingDescr* building_descr = egbase.tribes().get_building_descr(i);
148 lua_pushstring(L, building_descr->name().c_str());
149 lua_pushboolean(L, player.is_building_type_allowed(i));
150 lua_settable(L, -3);
151 }
152 return 1;
153 }
154
155 /* RST
156 .. attribute:: objectives
157
158 (RO) A table of name -> :class:`wl.game.Objective`. You can change
159 the objectives in this table and it will be reflected in the game. To add
160 a new item, use :meth:`add_objective`.
161 */
get_objectives(lua_State * L)162 int LuaPlayer::get_objectives(lua_State* L) {
163 lua_newtable(L);
164 for (const auto& pair : get_egbase(L).map().objectives()) {
165 lua_pushstring(L, pair.second->name());
166 to_lua<LuaObjective>(L, new LuaObjective(*pair.second));
167 lua_settable(L, -3);
168 }
169 return 1;
170 }
171
172 /* RST
173 .. attribute:: defeated
174
175 (RO) :const:`true` if this player was defeated, :const:`false` otherwise
176 */
get_defeated(lua_State * L)177 int LuaPlayer::get_defeated(lua_State* L) {
178 lua_pushboolean(L, get(L, get_egbase(L)).is_defeated());
179 return 1;
180 }
181
182 /* RST
183 .. attribute:: messages
184
185 (RO) An array of all the messages sent to the player. Note that you
186 can't add messages to this array, use :meth:`send_message` for that.
187 */
get_messages(lua_State * L)188 int LuaPlayer::get_messages(lua_State* L) {
189 Player& p = get(L, get_egbase(L));
190
191 lua_newtable(L);
192 uint32_t cidx = 1;
193 for (const auto& temp_message : p.messages()) {
194 lua_pushuint32(L, cidx++);
195 to_lua<LuaMessage>(L, new LuaMessage(player_number(), temp_message.first));
196 lua_rawset(L, -3);
197 }
198
199 return 1;
200 }
201
202 /* RST
203 .. attribute:: inbox
204
205 (RO) An array of the messages that are either read or new. Note that you
206 can't add messages to this array, use :meth:`send_message` for that.
207 */
get_inbox(lua_State * L)208 int LuaPlayer::get_inbox(lua_State* L) {
209 Player& p = get(L, get_egbase(L));
210
211 lua_newtable(L);
212 uint32_t cidx = 1;
213 for (const auto& temp_message : p.messages()) {
214 if (temp_message.second->status() == Message::Status::kArchived) {
215 continue;
216 }
217
218 lua_pushuint32(L, cidx++);
219 to_lua<LuaMessage>(L, new LuaMessage(player_number(), temp_message.first));
220 lua_rawset(L, -3);
221 }
222
223 return 1;
224 }
225
226 /* RST
227 .. attribute:: color
228
229 (RO) The playercolor assigned to this player, in hex notation.
230 */
get_color(lua_State * L)231 int LuaPlayer::get_color(lua_State* L) {
232 const PlayerNumber pnumber = get(L, get_egbase(L)).player_number();
233 lua_pushstring(L, kPlayerColors[pnumber - 1].hex_value());
234 return 1;
235 }
236
237 /* RST
238 .. attribute:: team
239
240 (RW) The team number of this player (0 means player is not in a team)
241
242 normally only reading should be enough, however it's a nice idea to have
243 a modular scenario, where teams form during the game.
244 */
set_team(lua_State * L)245 int LuaPlayer::set_team(lua_State* L) {
246 get(L, get_egbase(L)).set_team_number(luaL_checkinteger(L, -1));
247 return 0;
248 }
get_team(lua_State * L)249 int LuaPlayer::get_team(lua_State* L) {
250 lua_pushinteger(L, get(L, get_egbase(L)).team_number());
251 return 1;
252 }
253
254 /* RST
255 .. attribute:: tribe
256
257 Returns the player's tribe.
258
259 (RO) The :class:`~wl.Game.Tribe_description` for this player.
260 */
get_tribe(lua_State * L)261 int LuaPlayer::get_tribe(lua_State* L) {
262 return to_lua<LuaMaps::LuaTribeDescription>(
263 L, new LuaMaps::LuaTribeDescription(&get(L, get_egbase(L)).tribe()));
264 }
265
266 /* RST
267 .. attribute:: see_all
268
269 (RW) If you set this to true, the map will be completely visible for this
270 player.
271 */
set_see_all(lua_State * const L)272 int LuaPlayer::set_see_all(lua_State* const L) {
273 get(L, get_egbase(L)).set_see_all(luaL_checkboolean(L, -1));
274 return 0;
275 }
get_see_all(lua_State * const L)276 int LuaPlayer::get_see_all(lua_State* const L) {
277 lua_pushboolean(L, get(L, get_egbase(L)).see_all());
278 return 1;
279 }
280
281 /*
282 ==========================================================
283 LUA METHODS
284 ==========================================================
285 */
286
287 /* RST
288 .. method:: send_message(t, m[, opts])
289
290 Send a message to the player, the message will
291 appear in his inbox. Title or Message can be a
292 formatted using wideland's rich text.
293
294 :arg t: title of the message
295 :type t: :class:`string`
296
297 :arg m: text of the message
298 :type m: :class:`string`
299
300 Opts is a table of optional arguments and can be omitted. If it
301 exist it must contain string/value pairs of the following type:
302
303 :arg field: the field connected to this message. Default:
304 no field connected to message
305 :type field: :class:`wl.map.Field`
306
307 :arg status: status to attach to this message. can be 'new', 'read' or
308 'archived'. Default: "new"
309 :type status: :class:`string`
310
311 :arg popup: should the message window be opened for this message or not.
312 Default: :const:`false`
313 :type popup: :class:`boolean`
314
315 :arg icon: show a custom icon instead of the standard scenario message icon.
316 Default: "images/wui/messages/menu_toggle_objectives_menu.png""
317 :type icon: :class:`string` The icon's file path.
318
319 :arg heading: a longer message heading to be shown within the message.
320 If this is not set, `title` is used instead.
321 Default: ""
322 :type building: :class:`string`
323
324 :returns: the message created
325 :rtype: :class:`wl.game.Message`
326 */
send_message(lua_State * L)327 int LuaPlayer::send_message(lua_State* L) {
328 uint32_t n = lua_gettop(L);
329 const std::string title = luaL_checkstring(L, 2);
330 std::string heading = title;
331 const std::string body = luaL_checkstring(L, 3);
332 std::string icon = "images/wui/messages/menu_toggle_objectives_menu.png";
333 Coords c = Coords::null();
334 Message::Status st = Message::Status::kNew;
335 bool popup = false;
336 std::string sub_type = "";
337
338 Game& game = get_game(L);
339 Player& plr = get(L, game);
340
341 if (n == 4) {
342 // Optional arguments
343 lua_getfield(L, 4, "field");
344 if (!lua_isnil(L, -1)) {
345 c = (*get_user_class<LuaField>(L, -1))->coords();
346 }
347 lua_pop(L, 1);
348
349 lua_getfield(L, 4, "status");
350 if (!lua_isnil(L, -1)) {
351 const std::string s = luaL_checkstring(L, -1);
352 if (s == "new") {
353 st = Message::Status::kNew;
354 } else if (s == "read") {
355 st = Message::Status::kRead;
356 } else if (s == "archived") {
357 st = Message::Status::kArchived;
358 } else {
359 report_error(L, "Unknown message status: %s", s.c_str());
360 }
361 }
362 lua_pop(L, 1);
363
364 lua_getfield(L, 4, "popup");
365 if (!lua_isnil(L, -1)) {
366 popup = luaL_checkboolean(L, -1);
367 }
368 lua_pop(L, 1);
369
370 lua_getfield(L, 4, "icon");
371 if (!lua_isnil(L, -1)) {
372 const std::string s = luaL_checkstring(L, -1);
373 if (!s.empty()) {
374 icon = s;
375 }
376 }
377 lua_getfield(L, 4, "heading");
378 if (!lua_isnil(L, -1)) {
379 const std::string s = luaL_checkstring(L, -1);
380 if (!s.empty()) {
381 heading = s;
382 }
383 }
384 lua_getfield(L, 4, "sub_type");
385 if (!lua_isnil(L, -1)) {
386 const std::string s = luaL_checkstring(L, -1);
387 if (!s.empty()) {
388 sub_type = s;
389 }
390 }
391 }
392
393 MessageId const message = plr.add_message(
394 game, std::unique_ptr<Message>(new Message(Message::Type::kScenario, game.get_gametime(),
395 title, icon, heading, body, c, 0, sub_type, st)),
396 popup);
397
398 return to_lua<LuaMessage>(L, new LuaMessage(player_number(), message));
399 }
400
401 /* RST
402 .. method:: message_box(t, m[, opts])
403
404 Shows a message box to the player. While the message box is displayed the
405 game will not continue. Use this carefully and prefer
406 :meth:`send_message` because it is less interruptive, but nevertheless
407 for a set of narrative messages with map movements, this is still useful.
408
409 :arg t: title of the message
410 :type t: :class:`string`
411
412 :arg m: text of the message
413 :type m: :class:`string`
414
415 Opts is a table of optional arguments and can be omitted. If it
416 exist it must contain string/value pairs of the following type:
417
418 :arg field: The main view will be centered on this field when the box
419 pops up. Default: no field attached to message
420 :type field: :class:`wl.map.Field`
421
422 :arg w: width of message box in pixels. Default: 400.
423 :type w: :class:`integer`
424 :arg h: width of message box in pixels. Default: 300.
425 :type h: :class:`integer`
426 :arg posx: x position of window in pixels. Default: centered
427 :type posx: :class:`integer`
428 :arg posy: y position of window in pixels. Default: centered
429 :type posy: :class:`integer`
430
431 :returns: :const:`nil`
432 */
433 // UNTESTED
message_box(lua_State * L)434 int LuaPlayer::message_box(lua_State* L) {
435 Game& game = get_game(L);
436 // don't show message boxes in replays, cause they crash the game
437 if (game.game_controller()->get_game_type() == GameController::GameType::kReplay) {
438 return 1;
439 }
440
441 uint32_t w = 400;
442 uint32_t h = 300;
443 int32_t posx = -1;
444 int32_t posy = -1;
445 Coords coords = Coords::null();
446
447 #define CHECK_UINT(var) \
448 lua_getfield(L, -1, #var); \
449 if (!lua_isnil(L, -1)) \
450 var = luaL_checkuint32(L, -1); \
451 lua_pop(L, 1);
452
453 if (lua_gettop(L) == 4) {
454 CHECK_UINT(posx)
455 CHECK_UINT(posy)
456 CHECK_UINT(w)
457 CHECK_UINT(h)
458
459 // If a field has been defined, read the coordinates to jump to.
460 lua_getfield(L, 4, "field");
461 if (!lua_isnil(L, -1)) {
462 coords = (*get_user_class<LuaField>(L, -1))->coords();
463 }
464 lua_pop(L, 1);
465 }
466 #undef CHECK_UINT
467 std::unique_ptr<StoryMessageBox> mb(new StoryMessageBox(
468 &game, coords, luaL_checkstring(L, 2), luaL_checkstring(L, 3), posx, posy, w, h));
469
470 mb->run<UI::Panel::Returncodes>();
471
472 return 1;
473 }
474
475 /* RST
476 .. method:: sees_field(f)
477
478 Returns true if this field is currently seen by this player
479
480 :returns: :const:`true` or :const:`false`
481 :rtype: :class:`bool`
482 */
sees_field(lua_State * L)483 int LuaPlayer::sees_field(lua_State* L) {
484 EditorGameBase& egbase = get_egbase(L);
485
486 Widelands::MapIndex const i =
487 (*get_user_class<LuaField>(L, 2))->fcoords(L).field - &egbase.map()[0];
488
489 lua_pushboolean(L, get(L, egbase).vision(i) > 1);
490 return 1;
491 }
492
493 /* RST
494 .. method:: seen_field(f)
495
496 Returns true if this field has ever been seen by this player or
497 is currently seen
498
499 :returns: :const:`true` or :const:`false`
500 :rtype: :class:`bool`
501 */
seen_field(lua_State * L)502 int LuaPlayer::seen_field(lua_State* L) {
503 EditorGameBase& egbase = get_egbase(L);
504
505 Widelands::MapIndex const i =
506 (*get_user_class<LuaField>(L, 2))->fcoords(L).field - &egbase.map()[0];
507
508 lua_pushboolean(L, get(L, egbase).vision(i) >= 1);
509 return 1;
510 }
511
512 /* RST
513 .. method:: allow_buildings(what)
514
515 This method disables or enables buildings to build for the player. What
516 can either be the single string "all" or a list of strings containing
517 the names of the buildings that are allowed.
518
519 :see: :meth:`forbid_buildings`
520
521 :arg what: either "all" or an array containing the names of the allowed
522 buildings
523 :returns: :const:`nil`
524 */
allow_buildings(lua_State * L)525 int LuaPlayer::allow_buildings(lua_State* L) {
526 return allow_forbid_buildings(L, true);
527 }
528
529 /* RST
530 .. method:: forbid_buildings(what)
531
532 See :meth:`allow_buildings` for arguments. This is the opposite function.
533
534 :arg what: either "all" or an array containing the names of the allowed
535 buildings
536 :returns: :const:`nil`
537 */
forbid_buildings(lua_State * L)538 int LuaPlayer::forbid_buildings(lua_State* L) {
539 return allow_forbid_buildings(L, false);
540 }
541
542 /* RST
543 .. method:: add_objective(name, title, descr)
544
545 Add a new objective for this player. Will report an error, if an
546 Objective with the same name is already registered - note that the names
547 for the objectives are shared internally for all players, so not even
548 another player can have an objective with the same name.
549
550 :arg name: the name of the objective
551 :type name: :class:`string`
552 :arg title: the title of the objective that will be shown in the menu
553 :type title: :class:`string`
554 :arg body: the full text of the objective
555 :type body: :class:`string`
556
557 :returns: The objective class created
558 :rtype: :class:`wl.game.Objective`
559 */
add_objective(lua_State * L)560 int LuaPlayer::add_objective(lua_State* L) {
561 Game& game = get_game(L);
562
563 Map::Objectives* objectives = game.mutable_map()->mutable_objectives();
564
565 const std::string name = luaL_checkstring(L, 2);
566 if (objectives->count(name)) {
567 report_error(L, "An objective with the name '%s' already exists!", name.c_str());
568 }
569
570 Objective* o = new Objective(name);
571 o->set_done(false);
572 o->set_descname(luaL_checkstring(L, 3));
573 o->set_descr(luaL_checkstring(L, 4));
574 o->set_visible(true);
575
576 objectives->insert(std::make_pair(name, std::unique_ptr<Objective>(o)));
577 return to_lua<LuaObjective>(L, new LuaObjective(*o));
578 }
579
580 /* RST
581 .. method:: reveal_fields(fields)
582
583 Make these fields visible for the current player. The fields will remain
584 visible until they are hidden again. See also :ref:`field_animations` for
585 animated revealing.
586
587 :arg fields: The fields to reveal
588 :type fields: :class:`array` of :class:`wl.map.Fields`
589
590 :returns: :const:`nil`
591 */
reveal_fields(lua_State * L)592 int LuaPlayer::reveal_fields(lua_State* L) {
593 Game& game = get_game(L);
594 Player& p = get(L, game);
595
596 luaL_checktype(L, 2, LUA_TTABLE);
597
598 lua_pushnil(L); /* first key */
599 while (lua_next(L, 2) != 0) {
600 p.hide_or_reveal_field(
601 game.get_gametime(), (*get_user_class<LuaField>(L, -1))->coords(), SeeUnseeNode::kReveal);
602 lua_pop(L, 1);
603 }
604
605 return 0;
606 }
607
608 /* RST
609 .. method:: hide_fields(fields)
610
611 Make these fields hidden for the current player if they are not
612 seen by a military building. See also :ref:`field_animations` for
613 animated hiding.
614
615 :arg fields: The fields to hide
616 :type fields: :class:`array` of :class:`wl.map.Fields`
617
618 :arg unexplore: *Optional*. If `true`, the fields will be marked as completely unexplored.
619 :type unexplore: :class:`boolean`
620
621 :returns: :const:`nil`
622 */
hide_fields(lua_State * L)623 int LuaPlayer::hide_fields(lua_State* L) {
624 Game& game = get_game(L);
625 Player& p = get(L, game);
626
627 luaL_checktype(L, 2, LUA_TTABLE);
628 const SeeUnseeNode mode = (!lua_isnone(L, 3) && luaL_checkboolean(L, 3)) ?
629 SeeUnseeNode::kUnexplore :
630 SeeUnseeNode::kUnsee;
631
632 lua_pushnil(L); /* first key */
633 while (lua_next(L, 2) != 0) {
634 p.hide_or_reveal_field(
635 game.get_gametime(), (*get_user_class<LuaField>(L, -1))->coords(), mode);
636 lua_pop(L, 1);
637 }
638
639 return 0;
640 }
641
642 // TODO(GunChleoc): Savegame compatibility - remove after Build 21.
reveal_scenario(lua_State * L)643 int LuaPlayer::reveal_scenario(lua_State* L) {
644 if (get_game(L).get_ipl()->player_number() != player_number())
645 report_error(L, "Can only be called for interactive player!");
646
647 std::string scenario_name = luaL_checkstring(L, 2);
648
649 std::map<std::string, std::string> legacy_map{
650 {"frisians02", "fri02.wmf"}, {"frisians01", "fri01.wmf"},
651 {"atlanteans01", "atl01.wmf"}, {"empiretut04", "emp04.wmf"},
652 {"empiretut03", "emp03.wmf"}, {"empiretut02", "emp02.wmf"},
653 {"empiretut01", "emp01.wmf"}, {"barbariantut02", "bar02.wmf"},
654 {"barbariantut01", "bar01.wmf"}};
655
656 if (legacy_map.count(scenario_name)) {
657 Profile campvis(kCampVisFile.c_str());
658 campvis.pull_section("scenarios").set_bool(legacy_map[scenario_name].c_str(), true);
659 campvis.write(kCampVisFile.c_str(), false);
660 }
661
662 return 0;
663 }
664
665 // TODO(GunChleoc): Savegame compatibility - remove after Build 21.
reveal_campaign(lua_State *)666 int LuaPlayer::reveal_campaign(lua_State*) {
667 // Do nothing
668 return 0;
669 }
670
671 /* RST
672 .. method:: mark_scenario_as_solved(name)
673
674 Marks a campaign scenario as solved. Reads the scenario definition in
675 data/campaigns/campaigns.lua to check which scenario and/or campaign should be
676 revealed as a result. This only works for the interactive player and most likely
677 also only in single player games.
678
679 :arg name: name of the scenario to be marked as solved
680 :type name: :class:`string`
681 */
682 // UNTESTED
mark_scenario_as_solved(lua_State * L)683 int LuaPlayer::mark_scenario_as_solved(lua_State* L) {
684 if (get_game(L).get_ipl()->player_number() != player_number()) {
685 report_error(L, "Can only be called for interactive player!");
686 }
687
688 Profile campvis(kCampVisFile.c_str());
689 campvis.pull_section("scenarios").set_bool(luaL_checkstring(L, 2), true);
690 campvis.write(kCampVisFile.c_str(), false);
691
692 return 0;
693 }
694
695 /* RST
696 .. method:: get_ships()
697
698 :returns: array of player's ships
699 :rtype: :class:`array` or :class:`table`
700 */
get_ships(lua_State * L)701 int LuaPlayer::get_ships(lua_State* L) {
702 EditorGameBase& egbase = get_egbase(L);
703 PlayerNumber p = (get(L, egbase)).player_number();
704 lua_newtable(L);
705 uint32_t cidx = 1;
706 for (const auto& serial : egbase.player(p).ships()) {
707 Widelands::MapObject* obj = egbase.objects().get_object(serial);
708 assert(obj->descr().type() == Widelands::MapObjectType::SHIP);
709 upcast(Widelands::Ship, ship, obj);
710 lua_pushuint32(L, cidx++);
711 LuaMaps::upcasted_map_object_to_lua(L, ship);
712 lua_rawset(L, -3);
713 }
714 return 1;
715 }
716
717 /* RST
718 .. method:: get_buildings(which)
719
720 which can be either a single name or an array of names. In the first
721 case, the method returns an array of all Buildings that the player has of
722 this kind. If which is an array, the function returns a table of
723 (name,array of buildings) pairs.
724
725 :type which: name of building or array of building names
726 :rtype which: :class:`string` or :class:`array`
727 :returns: information about the players buildings
728 :rtype: :class:`array` or :class:`table`
729 */
get_buildings(lua_State * L)730 int LuaPlayer::get_buildings(lua_State* L) {
731 EditorGameBase& egbase = get_egbase(L);
732 Player& p = get(L, egbase);
733
734 // if only one string, convert to array so that we can use
735 // parse_building_list
736 bool return_array = true;
737 if (lua_isstring(L, -1)) {
738 const char* name = luaL_checkstring(L, -1);
739 lua_pop(L, 1);
740 lua_newtable(L);
741 lua_pushuint32(L, 1);
742 lua_pushstring(L, name);
743 lua_rawset(L, -3);
744 return_array = false;
745 }
746
747 std::vector<DescriptionIndex> houses;
748 parse_building_list(L, p.tribe(), houses);
749
750 lua_newtable(L);
751
752 uint32_t cidx = 1;
753 for (const DescriptionIndex& house : houses) {
754 const std::vector<Widelands::Player::BuildingStats>& vec = p.get_building_statistics(house);
755
756 if (return_array) {
757 lua_pushstring(L, p.tribe().get_building_descr(house)->name());
758 lua_newtable(L);
759 cidx = 1;
760 }
761
762 for (uint32_t l = 0; l < vec.size(); ++l) {
763 if (vec[l].is_constructionsite) {
764 continue;
765 }
766
767 lua_pushuint32(L, cidx++);
768 upcasted_map_object_to_lua(L, egbase.map()[vec[l].pos].get_immovable());
769 lua_rawset(L, -3);
770 }
771
772 if (return_array) {
773 lua_rawset(L, -3);
774 }
775 }
776 return 1;
777 }
778
779 /* RST
780 .. method:: get_suitability(building, field)
781
782 Returns whether this building type can be placed on this field. This
783 is mainly useful in initializations where buildings must be placed
784 automatically.
785
786 :arg building: name of the building description to check for
787 :type building: :class:`string`
788 :arg field: where the suitability should be checked
789 :type field: :class:`wl.map.Field`
790
791 :returns: whether the field has a suitable building plot for this building type
792 :rtype: :class:`boolean`
793 */
794 // UNTESTED
get_suitability(lua_State * L)795 int LuaPlayer::get_suitability(lua_State* L) {
796 Game& game = get_game(L);
797 const Tribes& tribes = game.tribes();
798
799 const char* name = luaL_checkstring(L, 2);
800 DescriptionIndex i = tribes.building_index(name);
801 if (!tribes.building_exists(i)) {
802 report_error(L, "Unknown building type: <%s>", name);
803 }
804
805 lua_pushboolean(L, tribes.get_building_descr(i)->suitability(
806 game.map(), (*get_user_class<LuaField>(L, 3))->fcoords(L)));
807 return 1;
808 }
809
810 /* RST
811 .. method:: allow_workers(what)
812
813 This will become the corresponding function to :meth:`allow_buildings`,
814 but at the moment this is only a stub that accepts only "all" as
815 argument. It then activates all workers for the player, that means all
816 workers are allowed to spawn in all warehouses.
817 */
allow_workers(lua_State * L)818 int LuaPlayer::allow_workers(lua_State* L) {
819
820 if (luaL_checkstring(L, 2) != std::string("all")) {
821 report_error(L, "Argument must be <all>!");
822 }
823
824 Game& game = get_game(L);
825 const TribeDescr& tribe = get(L, game).tribe();
826 Player& player = get(L, game);
827
828 const std::vector<DescriptionIndex>& worker_types_without_cost =
829 tribe.worker_types_without_cost();
830
831 for (const DescriptionIndex& worker_index : tribe.workers()) {
832 const WorkerDescr* worker_descr = game.tribes().get_worker_descr(worker_index);
833 if (!worker_descr->is_buildable()) {
834 continue;
835 }
836 player.allow_worker_type(worker_index, true);
837
838 if (worker_descr->buildcost().empty()) {
839 // Workers of this type can be spawned in warehouses. Start it.
840 uint8_t worker_types_without_cost_index = 0;
841 for (;; ++worker_types_without_cost_index) {
842 assert(worker_types_without_cost_index < worker_types_without_cost.size());
843 if (worker_types_without_cost.at(worker_types_without_cost_index) == worker_index) {
844 break;
845 }
846 }
847 for (const auto& economy : player.economies()) {
848 for (Warehouse* warehouse : economy.second->warehouses()) {
849 warehouse->enable_spawn(game, worker_types_without_cost_index);
850 }
851 }
852 }
853 }
854 return 0;
855 }
856
857 /* RST
858 .. method:: switchplayer(playernumber)
859
860 If *this* is the local player (the player set in interactive player)
861 switch to the player with playernumber
862 */
switchplayer(lua_State * L)863 int LuaPlayer::switchplayer(lua_State* L) {
864 Game& game = get_game(L);
865
866 uint8_t newplayer = luaL_checkinteger(L, -1);
867 InteractivePlayer* ipl = game.get_ipl();
868 // only switch, if this is our player!
869 if (ipl->player_number() == player_number()) {
870 ipl->set_player_number(newplayer);
871 }
872 return 0;
873 }
874
875 /* RST
876 .. method:: produced_wares_count(what)
877
878 Returns count of wares produced by the player up to now.
879 'what' can be either an "all" or single ware name or an array of names. If single
880 ware name is given, integer is returned, otherwise the table is returned.
881 */
get_produced_wares_count(lua_State * L)882 int LuaPlayer::get_produced_wares_count(lua_State* L) {
883 Player& p = get(L, get_egbase(L));
884 const TribeDescr& tribe = p.tribe();
885 int32_t nargs = lua_gettop(L);
886 if (nargs != 2) {
887 report_error(L, "One argument is required for produced_wares_count()");
888 }
889 std::vector<DescriptionIndex> requested_wares;
890 DescriptionIndex single_ware = INVALID_INDEX;
891
892 LuaMaps::parse_wares_workers_list(L, tribe, &single_ware, &requested_wares, true);
893
894 if (single_ware != INVALID_INDEX) {
895 // We return single number
896 lua_pushuint32(L, p.get_current_produced_statistics(single_ware));
897 } else {
898 // We return array of ware:quantity
899 assert(!requested_wares.empty());
900 lua_newtable(L);
901 for (const DescriptionIndex& idx : requested_wares) {
902 lua_pushstring(L, tribe.get_ware_descr(idx)->name());
903 lua_pushuint32(L, p.get_current_produced_statistics(idx));
904 lua_settable(L, -3);
905 }
906 }
907
908 return 1;
909 }
910
911 /* RST
912 .. method:: is_attack_forbidden(who)
913
914 Returns true if this player is currently forbidden to attack the player with the specified
915 player number. Note that the return value `false` does not necessarily mean that this
916 player *can* attack the other player, as they might for example be in the same team.
917
918 :arg who: player number of the player to query
919 :type who: :class:`int`
920 :rtype: :class:`boolean`
921 */
is_attack_forbidden(lua_State * L)922 int LuaPlayer::is_attack_forbidden(lua_State* L) {
923 lua_pushboolean(L, get(L, get_egbase(L)).is_attack_forbidden(luaL_checkinteger(L, 2)));
924 return 1;
925 }
926
927 /* RST
928 .. method:: set_attack_forbidden(who, forbid)
929
930 Sets whether this player is forbidden to attack the player with the specified
931 player number. Note that setting this to `false` does not necessarily mean that this
932 player *can* attack the other player, as they might for example be in the same team.
933
934 :arg who: player number of the player to query
935 :type who: :class:`int`
936 :arg forbid: Whether to allow or forbid attacks
937 :type forbid: :class:`boolean`
938 */
set_attack_forbidden(lua_State * L)939 int LuaPlayer::set_attack_forbidden(lua_State* L) {
940 get(L, get_egbase(L)).set_attack_forbidden(luaL_checkinteger(L, 2), luaL_checkboolean(L, 3));
941 return 0;
942 }
943
944 /*
945 ==========================================================
946 C METHODS
947 ==========================================================
948 */
parse_building_list(lua_State * L,const TribeDescr & tribe,std::vector<DescriptionIndex> & rv)949 void LuaPlayer::parse_building_list(lua_State* L,
950 const TribeDescr& tribe,
951 std::vector<DescriptionIndex>& rv) {
952 EditorGameBase& egbase = get_egbase(L);
953 const Tribes& tribes = egbase.tribes();
954 if (lua_isstring(L, -1)) {
955 std::string opt = luaL_checkstring(L, -1);
956 if (opt != "all") {
957 report_error(L, "'%s' was not understood as argument!", opt.c_str());
958 }
959 // Only act on buildings that the tribe has or could conquer
960 const TribeDescr& tribe_descr = get(L, egbase).tribe();
961 for (size_t i = 0; i < tribes.nrbuildings(); ++i) {
962 const DescriptionIndex& building_index = static_cast<DescriptionIndex>(i);
963 const BuildingDescr& descr = *tribe_descr.get_building_descr(building_index);
964 if (tribe_descr.has_building(building_index) ||
965 descr.type() == MapObjectType::MILITARYSITE) {
966 rv.push_back(building_index);
967 }
968 }
969 } else {
970 // array of strings argument
971 luaL_checktype(L, -1, LUA_TTABLE);
972
973 lua_pushnil(L);
974 while (lua_next(L, -2) != 0) {
975 const char* name = luaL_checkstring(L, -1);
976 DescriptionIndex i = tribe.building_index(name);
977 if (!tribes.building_exists(i)) {
978 report_error(L, "Unknown building type: '%s'", name);
979 }
980
981 rv.push_back(i);
982
983 lua_pop(L, 1); // pop value
984 }
985 }
986 }
987
allow_forbid_buildings(lua_State * L,bool allow)988 int LuaPlayer::allow_forbid_buildings(lua_State* L, bool allow) {
989 Player& p = get(L, get_egbase(L));
990
991 std::vector<DescriptionIndex> houses;
992 parse_building_list(L, p.tribe(), houses);
993
994 for (const DescriptionIndex& house : houses) {
995 p.allow_building_type(house, allow);
996 }
997 return 0;
998 }
999
1000 /* RST
1001 Objective
1002 ---------
1003
1004 .. class:: Objective
1005
1006 This represents an Objective, a goal for the player in the game. This is
1007 mainly for displaying to the user, but each objective also has a
1008 :attr:`done` which can be set by the scripter to define if this is done. Use
1009 :attr:`visible` to hide it from the user.
1010 */
1011 const char LuaObjective::className[] = "Objective";
1012 const MethodType<LuaObjective> LuaObjective::Methods[] = {
1013 METHOD(LuaObjective, remove), METHOD(LuaObjective, __eq), {nullptr, nullptr},
1014 };
1015 const PropertyType<LuaObjective> LuaObjective::Properties[] = {
1016 PROP_RO(LuaObjective, name), PROP_RW(LuaObjective, title), PROP_RW(LuaObjective, body),
1017 PROP_RW(LuaObjective, visible), PROP_RW(LuaObjective, done), {nullptr, nullptr, nullptr},
1018 };
1019
LuaObjective(const Widelands::Objective & o)1020 LuaObjective::LuaObjective(const Widelands::Objective& o) : name_(o.name()) {
1021 }
1022
__persist(lua_State * L)1023 void LuaObjective::__persist(lua_State* L) {
1024 PERS_STRING("name", name_);
1025 }
__unpersist(lua_State * L)1026 void LuaObjective::__unpersist(lua_State* L) {
1027 UNPERS_STRING("name", name_)
1028 }
1029
1030 /*
1031 ==========================================================
1032 PROPERTIES
1033 ==========================================================
1034 */
1035 /* RST
1036 .. attribute:: name
1037
1038 (RO) the internal name. You can reference this object via
1039 :attr:`wl.game.Player.objectives` with :attr:`name` as key.
1040 */
get_name(lua_State * L)1041 int LuaObjective::get_name(lua_State* L) {
1042 Objective& o = get(L, get_game(L));
1043 lua_pushstring(L, o.name().c_str());
1044 return 1;
1045 }
1046 /* RST
1047 .. attribute:: title
1048
1049 (RW) The line that is shown in the objectives menu
1050 */
get_title(lua_State * L)1051 int LuaObjective::get_title(lua_State* L) {
1052 Objective& o = get(L, get_game(L));
1053 lua_pushstring(L, o.descname().c_str());
1054 return 1;
1055 }
set_title(lua_State * L)1056 int LuaObjective::set_title(lua_State* L) {
1057 Objective& o = get(L, get_game(L));
1058 o.set_descname(luaL_checkstring(L, -1));
1059 return 0;
1060 }
1061 /* RST
1062 .. attribute:: body
1063
1064 (RW) The complete text of this objective. Can be Widelands Richtext.
1065 */
get_body(lua_State * L)1066 int LuaObjective::get_body(lua_State* L) {
1067 Objective& o = get(L, get_game(L));
1068 lua_pushstring(L, o.descr().c_str());
1069 return 1;
1070 }
set_body(lua_State * L)1071 int LuaObjective::set_body(lua_State* L) {
1072 Objective& o = get(L, get_game(L));
1073 o.set_descr(luaL_checkstring(L, -1));
1074 return 0;
1075 }
1076 /* RST
1077 .. attribute:: visible
1078
1079 (RW) is this objective shown in the objectives menu
1080 */
get_visible(lua_State * L)1081 int LuaObjective::get_visible(lua_State* L) {
1082 Objective& o = get(L, get_game(L));
1083 lua_pushboolean(L, o.visible());
1084 return 1;
1085 }
set_visible(lua_State * L)1086 int LuaObjective::set_visible(lua_State* L) {
1087 Objective& o = get(L, get_game(L));
1088 o.set_visible(luaL_checkboolean(L, -1));
1089 return 0;
1090 }
1091 /* RST
1092 .. attribute:: done
1093
1094 (RW) defines if this objective is already fulfilled. If done is
1095 :const`true`, the objective will not be shown to the user, no matter what.
1096 :attr:`visible` is set to. A savegame will be created when this attribute
1097 is changed to :const`true`.
1098
1099 */
get_done(lua_State * L)1100 int LuaObjective::get_done(lua_State* L) {
1101 Objective& o = get(L, get_game(L));
1102 lua_pushboolean(L, o.done());
1103 return 1;
1104 }
set_done(lua_State * L)1105 int LuaObjective::set_done(lua_State* L) {
1106 Objective& o = get(L, get_game(L));
1107 o.set_done(luaL_checkboolean(L, -1));
1108
1109 const int32_t autosave = get_config_int("autosave", 0);
1110 if (autosave <= 0) {
1111 return 0;
1112 }
1113
1114 if (o.done()) {
1115 /** TRANSLATORS: File name for saving objective achieved */
1116 /** TRANSLATORS: %1% = map name. %2% = achievement name */
1117 std::string filename = _("%1% (%2%)");
1118 i18n::Textdomain td("maps");
1119 filename =
1120 (boost::format(filename) % _(get_egbase(L).map().get_name()) % o.descname().c_str()).str();
1121 get_game(L).save_handler().request_save(filename);
1122 }
1123 return 0;
1124 }
1125
1126 /*
1127 ==========================================================
1128 LUA METHODS
1129 ==========================================================
1130 */
remove(lua_State * L)1131 int LuaObjective::remove(lua_State* L) {
1132 Game& g = get_game(L);
1133 // The next call checks if the Objective still exists
1134 get(L, g);
1135 g.mutable_map()->mutable_objectives()->erase(name_);
1136 return 0;
1137 }
1138
__eq(lua_State * L)1139 int LuaObjective::__eq(lua_State* L) {
1140 const Map::Objectives& objectives = get_game(L).map().objectives();
1141
1142 const Map::Objectives::const_iterator me = objectives.find(name_);
1143 const Map::Objectives::const_iterator other =
1144 objectives.find((*get_user_class<LuaObjective>(L, 2))->name_);
1145
1146 lua_pushboolean(L, (me != objectives.end() && other != objectives.end()) &&
1147 (me->second->name() == other->second->name()));
1148 return 1;
1149 }
1150
1151 /*
1152 ==========================================================
1153 C METHODS
1154 ==========================================================
1155 */
get(lua_State * L,Widelands::Game & g)1156 Objective& LuaObjective::get(lua_State* L, Widelands::Game& g) {
1157 Map::Objectives* objectives = g.mutable_map()->mutable_objectives();
1158 Map::Objectives::iterator i = objectives->find(name_);
1159 if (i == objectives->end()) {
1160 report_error(L, "Objective with name '%s' doesn't exist!", name_.c_str());
1161 }
1162 return *i->second;
1163 }
1164
1165 /* RST
1166 Message
1167 ---------
1168
1169 .. class:: Message
1170
1171 This represents a message in the Message Box of a given user.
1172 */
1173 const char LuaMessage::className[] = "Message";
1174 const MethodType<LuaMessage> LuaMessage::Methods[] = {
1175 METHOD(LuaMessage, __eq), {nullptr, nullptr},
1176 };
1177 const PropertyType<LuaMessage> LuaMessage::Properties[] = {
1178 PROP_RO(LuaMessage, title), PROP_RO(LuaMessage, body), PROP_RO(LuaMessage, sent),
1179 PROP_RO(LuaMessage, field), PROP_RW(LuaMessage, status), PROP_RO(LuaMessage, heading),
1180 PROP_RO(LuaMessage, icon_name), {nullptr, nullptr, nullptr},
1181 };
1182
LuaMessage(uint8_t plr,MessageId id)1183 LuaMessage::LuaMessage(uint8_t plr, MessageId id) {
1184 player_number_ = plr;
1185 message_id_ = id;
1186 }
1187
__persist(lua_State * L)1188 void LuaMessage::__persist(lua_State* L) {
1189 PERS_UINT32("player", player_number_);
1190 PERS_UINT32("msg_idx", get_mos(L)->message_savers[player_number_ - 1][message_id_].value());
1191 }
__unpersist(lua_State * L)1192 void LuaMessage::__unpersist(lua_State* L) {
1193 UNPERS_UINT32("player", player_number_)
1194 uint32_t midx = 0;
1195 UNPERS_UINT32("msg_idx", midx)
1196 message_id_ = MessageId(midx);
1197 }
1198
1199 /*
1200 ==========================================================
1201 PROPERTIES
1202 ==========================================================
1203 */
1204
1205 /* RST
1206 .. attribute:: title
1207
1208 (RO) The title of this message
1209 */
get_title(lua_State * L)1210 int LuaMessage::get_title(lua_State* L) {
1211 lua_pushstring(L, get(L, get_game(L)).title());
1212 return 1;
1213 }
1214 /* RST
1215 .. attribute:: body
1216
1217 (RO) The body of this message
1218 */
get_body(lua_State * L)1219 int LuaMessage::get_body(lua_State* L) {
1220 lua_pushstring(L, get(L, get_game(L)).body());
1221 return 1;
1222 }
1223
1224 /* RST
1225 .. attribute:: sent
1226
1227 (RO) The game time in milliseconds when this message was sent
1228 */
get_sent(lua_State * L)1229 int LuaMessage::get_sent(lua_State* L) {
1230 lua_pushuint32(L, get(L, get_game(L)).sent());
1231 return 1;
1232 }
1233
1234 /* RST
1235 .. attribute:: field
1236
1237 (RO) The field that corresponds to this Message.
1238 */
get_field(lua_State * L)1239 int LuaMessage::get_field(lua_State* L) {
1240 Coords c = get(L, get_game(L)).position();
1241 if (c == Coords::null()) {
1242 return 0;
1243 }
1244 return to_lua<LuaField>(L, new LuaField(c));
1245 }
1246
1247 /* RST
1248 .. attribute:: status
1249
1250 (RW) The status of the message. Can be either of
1251
1252 * new
1253 * read
1254 * archived
1255 */
get_status(lua_State * L)1256 int LuaMessage::get_status(lua_State* L) {
1257 switch (get(L, get_game(L)).status()) {
1258 case Message::Status::kNew:
1259 lua_pushstring(L, "new");
1260 break;
1261 case Message::Status::kRead:
1262 lua_pushstring(L, "read");
1263 break;
1264 case Message::Status::kArchived:
1265 lua_pushstring(L, "archived");
1266 break;
1267 }
1268 return 1;
1269 }
set_status(lua_State * L)1270 int LuaMessage::set_status(lua_State* L) {
1271 Message::Status status = Message::Status::kNew;
1272 std::string s = luaL_checkstring(L, -1);
1273 if (s == "new") {
1274 status = Message::Status::kNew;
1275 } else if (s == "read") {
1276 status = Message::Status::kRead;
1277 } else if (s == "archived") {
1278 status = Message::Status::kArchived;
1279 } else {
1280 report_error(L, "Invalid message status <%s>!", s.c_str());
1281 }
1282
1283 get_plr(L, get_game(L)).get_messages()->set_message_status(message_id_, status);
1284
1285 return 0;
1286 }
1287
1288 /* RST
1289 .. attribute:: heading
1290
1291 (RO) The long heading of this message that is shown in the body
1292 */
get_heading(lua_State * L)1293 int LuaMessage::get_heading(lua_State* L) {
1294 lua_pushstring(L, get(L, get_game(L)).heading());
1295 return 1;
1296 }
1297
1298 /* RST
1299 .. attribute:: icon_name
1300
1301 (RO) The filename for the icon that is shown with the message title
1302 */
get_icon_name(lua_State * L)1303 int LuaMessage::get_icon_name(lua_State* L) {
1304 lua_pushstring(L, get(L, get_game(L)).icon_filename());
1305 return 1;
1306 }
1307
1308 /*
1309 ==========================================================
1310 LUA METHODS
1311 ==========================================================
1312 */
__eq(lua_State * L)1313 int LuaMessage::__eq(lua_State* L) {
1314 lua_pushboolean(L, message_id_ == (*get_user_class<LuaMessage>(L, 2))->message_id_);
1315 return 1;
1316 }
1317
1318 /*
1319 ==========================================================
1320 C METHODS
1321 ==========================================================
1322 */
get_plr(lua_State * L,Widelands::Game & game)1323 Player& LuaMessage::get_plr(lua_State* L, Widelands::Game& game) {
1324 if (player_number_ > kMaxPlayers) {
1325 report_error(L, "Illegal player number %i", player_number_);
1326 }
1327 Player* rv = game.get_player(player_number_);
1328 if (!rv) {
1329 report_error(L, "Player with the number %i does not exist", player_number_);
1330 }
1331 return *rv;
1332 }
get(lua_State * L,Widelands::Game & game)1333 const Message& LuaMessage::get(lua_State* L, Widelands::Game& game) {
1334 const Message* rv = get_plr(L, game).messages()[message_id_];
1335 if (!rv) {
1336 report_error(L, "This message has been deleted!");
1337 }
1338 return *rv;
1339 }
1340
1341 /* RST
1342 .. function:: report_result(plr, result[, info = ""])
1343
1344 Reports the game ending to the metaserver if this is an Internet
1345 network game. Otherwise, does nothing.
1346
1347 :arg plr: The Player to report results for.
1348 :type plr: :class:`~wl.game.Player`
1349 :arg result: The player result (0: lost, 1: won, 2: resigned)
1350 :type result: :class:`number`
1351 :arg info: a string containing extra data for this particular win
1352 condition. This will vary from game type to game type. See
1353 :class:`PlayerEndStatus` for allowed values
1354 :type info: :class:`string`
1355
1356 */
1357 // TODO(sirver): this should be a method of wl.Game(). Fix for b19.
L_report_result(lua_State * L)1358 static int L_report_result(lua_State* L) {
1359 std::string info;
1360 if (lua_gettop(L) >= 3) {
1361 info = luaL_checkstring(L, 3);
1362 }
1363
1364 Widelands::PlayerEndResult result =
1365 static_cast<Widelands::PlayerEndResult>(luaL_checknumber(L, 2));
1366
1367 get_game(L).game_controller()->report_result(
1368 (*get_user_class<LuaPlayer>(L, 1))->get(L, get_game(L)).player_number(), result, info);
1369 return 0;
1370 }
1371
1372 /*
1373 * ========================================================================
1374 * MODULE FUNCTIONS
1375 * ========================================================================
1376 */
1377 const static struct luaL_Reg wlgame[] = {{"report_result", &L_report_result}, {nullptr, nullptr}};
1378
luaopen_wlgame(lua_State * L)1379 void luaopen_wlgame(lua_State* L) {
1380 lua_getglobal(L, "wl"); // S: wl_table
1381 lua_pushstring(L, "game"); // S: wl_table "game"
1382 luaL_newlib(L, wlgame); // S: wl_table "game" wl.game_table
1383 lua_settable(L, -3); // S: wl_table
1384 lua_pop(L, 1); // S:
1385
1386 register_class<LuaPlayer>(L, "game", true);
1387 add_parent<LuaPlayer, LuaBases::LuaPlayerBase>(L);
1388 lua_pop(L, 1); // Pop the meta table
1389
1390 register_class<LuaObjective>(L, "game");
1391 register_class<LuaMessage>(L, "game");
1392 }
1393 } // namespace LuaGame
1394