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