1 /*
2    Copyright (C) 2009 - 2018 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include <cstddef>
18 #include <string>
19 #include "scripting/lua_common.hpp"
20 #include "units/ptr.hpp"
21 
22 struct lua_State;
23 class lua_unit;
24 struct map_location;
25 
26 /**
27  * Test if a Lua value is a unit
28  */
29 bool luaW_isunit(lua_State *, int index);
30 
31 /**
32  * Converts a Lua value to a unit pointer.
33  */
34 unit* luaW_tounit(lua_State *L, int index, bool only_on_map = false);
35 
36 /**
37  * Converts a Lua value to a unit pointer.
38  */
39 unit& luaW_checkunit(lua_State *L, int index, bool only_on_map = false);
40 
41 /**
42  * Pushes a private unit on the stack.
43  */
44 lua_unit* luaW_pushlocalunit(lua_State *L, unit& u);
45 
46 /**
47  * Similar to luaW_tounit but returns a unit_ptr; use this instead of
48  * luaW_tounit when using an api that needs unit_ptr.
49  */
50 unit_ptr luaW_tounit_ptr(lua_State *L, int index, bool only_on_map);
51 
52 /**
53  * Similar to luaW_checkunit but returns a unit_ptr; use this instead of
54  * luaW_checkunit when using an api that needs unit_ptr.
55  */
56 unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map);
57 
58 /**
59  * Similar to luaW_tounit but returns a lua_unit; use this if you need
60  * to handle map and recall units differently, for example.
61  *
62  * Note that this only returns null if the element on the stack was not a unit,
63  * so it may be an invalid unit.
64  */
65 lua_unit* luaW_tounit_ref(lua_State *L, int index);
66 
67 /**
68  * Similar to luaW_checkunit but returns a lua_unit; use this if you need
69  * to handle map and recall units differently, for example.
70  */
71 lua_unit* luaW_checkunit_ref(lua_State *L, int index);
72 
73 
74 /**
75  * Storage for a unit, either owned by the Lua code (#ptr != 0), a
76  * local variable unit (c_ptr != 0), on a recall list (#side != 0), or on the map.
77  * Shared units are represented by their underlying ID (#uid).
78  */
79 class lua_unit
80 {
81 	size_t uid;
82 	unit_ptr ptr;
83 	int side;
84 	unit* c_ptr;
85 	lua_unit(const lua_unit&) = delete;
86 	lua_unit& operator=(const lua_unit&) = delete;
87 
88 	template<typename... Args>
89 	friend lua_unit* luaW_pushunit(lua_State *L, Args... args);
90 	friend lua_unit* luaW_pushlocalunit(lua_State *L, unit& u);
91 	static void setmetatable(lua_State *L);
92 public:
lua_unit(size_t u)93 	lua_unit(size_t u): uid(u), ptr(), side(0), c_ptr() {}
lua_unit(unit_ptr u)94 	lua_unit(unit_ptr u): uid(0), ptr(u), side(0), c_ptr() {}
lua_unit(int s,size_t u)95 	lua_unit(int s, size_t u): uid(u), ptr(), side(s), c_ptr() {}
lua_unit(unit & u)96 	lua_unit(unit& u): uid(0), ptr(), side(0), c_ptr(&u) {}
97 	~lua_unit();
98 
on_map() const99 	bool on_map() const { return !ptr && side == 0; }
on_recall_list() const100 	int on_recall_list() const { return side; }
101 
102 	unit* get();
103 	unit_ptr get_shared();
104 
operator ->()105 	unit* operator->() {return get();}
operator *()106 	unit& operator*() {return *get();}
107 
clear_ref()108 	void clear_ref() { uid = 0; ptr = unit_ptr(); side = 0; c_ptr = nullptr; }
109 	// Clobbers loc
110 	bool put_map(const map_location &loc);
111 };
112 
113 template<typename... Args>
luaW_pushunit(lua_State * L,Args...args)114 inline lua_unit* luaW_pushunit(lua_State *L, Args... args) {
115 	lua_unit* lu = new(L) lua_unit(args...);
116 	lua_unit::setmetatable(L);
117 	return lu;
118 }
119 
120 namespace lua_units {
121 	std::string register_metatables(lua_State *L);
122 }
123