1 /*
2 * See Licensing and Copyright notice in naev.h
3 */
4
5 /**
6 * @file nlua_evt.c
7 *
8 * @brief Handles the event Lua bindings.
9 */
10
11
12 #include "nlua_evt.h"
13
14 #include "naev.h"
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include "nstring.h"
19 #include <math.h>
20
21 #include <lua.h>
22 #include <lauxlib.h>
23
24 #include "nlua.h"
25 #include "nluadef.h"
26 #include "nlua_system.h"
27 #include "nlua_hook.h"
28 #include "log.h"
29 #include "event.h"
30 #include "mission.h"
31 #include "player.h"
32 #include "npc.h"
33 #include "ndata.h"
34
35
36 /**
37 * @brief Event system Lua bindings.
38 *
39 * An example would be:
40 * @code
41 * evt.finish() -- finishes the event
42 * @endcode
43 *
44 * @luamod evt
45 */
46
47
48 /*
49 * libraries
50 */
51 /* evt */
52 static int evt_npcAdd( lua_State *L );
53 static int evt_npcRm( lua_State *L );
54 static int evt_finish( lua_State *L );
55 static int evt_save( lua_State *L );
56 static int evt_claim( lua_State *L );
57 static const luaL_reg evt_methods[] = {
58 { "npcAdd", evt_npcAdd },
59 { "npcRm", evt_npcRm },
60 { "save", evt_save },
61 { "finish", evt_finish },
62 { "claim", evt_claim },
63 {0,0}
64 }; /**< Mission Lua methods. */
65
66
67 /*
68 * individual library loading
69 */
70 /**
71 * @brief Loads the event Lua library.
72 * @param L Lua state.
73 */
nlua_loadEvt(nlua_env env)74 int nlua_loadEvt( nlua_env env )
75 {
76 nlua_register(env, "evt", evt_methods, 0);
77 return 0;
78 }
79
80
81 /**
82 * @brief Sets up the Lua environment to run a function.
83 */
event_setupLua(Event_t * ev,const char * func)84 void event_setupLua( Event_t *ev, const char *func )
85 {
86 /* Set up event pointer. */
87 lua_pushlightuserdata( naevL, ev );
88 nlua_setenv( ev->env, "__evt" );
89
90 /* Get function. */
91 nlua_getenv(ev->env, func );
92 }
93
94
95 /**
96 * @brief Runs the Lua for an event.
97 */
event_runLua(Event_t * ev,const char * func)98 int event_runLua( Event_t *ev, const char *func )
99 {
100 int ret;
101 event_setupLua( ev, func );
102 ret = event_runLuaFunc( ev, func, 0 );
103 return ret;
104 }
105
106
107 /**
108 * @brief Gets the current running event from user data.
109 *
110 * This should ONLY be called below an nlua_pcall, so __NLUA_CURENV is set
111 */
event_getFromLua(lua_State * L)112 Event_t *event_getFromLua( lua_State *L )
113 {
114 Event_t *ev;
115
116 nlua_getenv(__NLUA_CURENV, "__evt");
117 ev = (Event_t*) lua_touserdata( L, -1 );
118 lua_pop( L, 1 );
119 return ev;
120 }
121
122
123 /**
124 * @brief Runs a Lua func with nargs.
125 *
126 * @return -1 on error, 1 on misn.finish() call, 2 if event got deleted
127 * and 0 normally.
128 */
event_runLuaFunc(Event_t * ev,const char * func,int nargs)129 int event_runLuaFunc( Event_t *ev, const char *func, int nargs )
130 {
131 int ret;
132 const char* err;
133 int evt_delete;
134
135 ret = nlua_pcall(ev->env, nargs, 0);
136 if (ret != 0) { /* error has occurred */
137 err = (lua_isstring(naevL,-1)) ? lua_tostring(naevL,-1) : NULL;
138 if ((err==NULL) || (strcmp(err,NLUA_DONE)!=0)) {
139 WARN("Event '%s' -> '%s': %s",
140 event_getData(ev->id), func, (err) ? err : "unknown error");
141 ret = -1;
142 }
143 else
144 ret = 1;
145 lua_pop(naevL, 1);
146 }
147
148 /* Time to remove the event. */
149 nlua_getenv(ev->env, "__evt_delete");
150 evt_delete = lua_toboolean(naevL,-1);
151 lua_pop(naevL,1);
152 if (evt_delete) {
153 ret = 2;
154 event_remove( ev->id );
155 }
156
157 return ret;
158 }
159
160
161 /**
162 * @brief Adds an NPC.
163 *
164 * @usage npc_id = evt.npcAdd( "my_func", "Mr. Test", "none", "A test." ) -- Creates an NPC.
165 *
166 * @luatparam string func Name of the function to run when approaching, gets passed the npc_id when called.
167 * @luatparam string name Name of the NPC
168 * @luatparam string portrait Portrait to use for the NPC (from GFX_PATH/portraits/).
169 * @luatparam string desc Description associated to the NPC.
170 * @luatparam[opt=5] number priority Optional priority argument (highest is 0, lowest is 10).
171 * @luatreturn number The ID of the NPC to pass to npcRm.
172 * @luafunc npcAdd( func, name, portrait, desc, priority )
173 */
evt_npcAdd(lua_State * L)174 static int evt_npcAdd( lua_State *L )
175 {
176 unsigned int id;
177 int priority;
178 const char *func, *name, *gfx, *desc;
179 char portrait[PATH_MAX];
180 Event_t *cur_event;
181
182 /* Handle parameters. */
183 func = luaL_checkstring(L, 1);
184 name = luaL_checkstring(L, 2);
185 gfx = luaL_checkstring(L, 3);
186 desc = luaL_checkstring(L, 4);
187
188 /* Optional priority. */
189 if (lua_gettop(L) > 4)
190 priority = luaL_checkint( L, 5 );
191 else
192 priority = 5;
193
194 /* Set path. */
195 nsnprintf( portrait, PATH_MAX, GFX_PATH"portraits/%s.png", gfx );
196
197 cur_event = event_getFromLua(L);
198
199 /* Add npc. */
200 id = npc_add_event( cur_event->id, func, name, priority, portrait, desc );
201
202 /* Return ID. */
203 if (id > 0) {
204 lua_pushnumber( L, id );
205 return 1;
206 }
207 return 0;
208 }
209
210
211 /**
212 * @brief Removes an NPC.
213 *
214 * @usage evt.npcRm( npc_id )
215 *
216 * @luatparam number id ID of the NPC to remove.
217 * @luafunc npcRm( id )
218 */
evt_npcRm(lua_State * L)219 static int evt_npcRm( lua_State *L )
220 {
221 unsigned int id;
222 int ret;
223 Event_t *cur_event;
224
225 id = luaL_checklong(L, 1);
226
227 cur_event = event_getFromLua(L);
228 ret = npc_rm_event( id, cur_event->id );
229
230 if (ret != 0)
231 NLUA_ERROR(L, "Invalid NPC ID!");
232 return 0;
233 }
234
235
236 /**
237 * @brief Finishes the event.
238 *
239 * @luatparam[opt=false] boolean properly If true and the event is unique it marks the event
240 * as completed. If false it deletes the event but
241 * doesn't mark it as completed.
242 * @luafunc finish( properly )
243 */
evt_finish(lua_State * L)244 static int evt_finish( lua_State *L )
245 {
246 int b;
247 Event_t *cur_event;
248
249 cur_event = event_getFromLua(L);
250
251 b = lua_toboolean(L,1);
252 lua_pushboolean( L, 1 );
253 nlua_setenv(cur_event->env, "__evt_delete");
254
255 if (b && event_isUnique(cur_event->id))
256 player_eventFinished( cur_event->data );
257
258 lua_pushstring(L, NLUA_DONE);
259 lua_error(L); /* shouldn't return */
260
261 return 0;
262 }
263
264
265 /**
266 * @brief Saves an event.
267 *
268 * @usage evt.save() -- Saves an event, which is by default disabled.
269 *
270 * @luatparam[opt=true] boolean enable If true sets the event to save, otherwise tells the event to not save.
271 * @luafunc save( enable )
272 */
evt_save(lua_State * L)273 static int evt_save( lua_State *L )
274 {
275 int b;
276 Event_t *cur_event;
277 if (lua_gettop(L)==0)
278 b = 1;
279 else
280 b = lua_toboolean(L,1);
281 cur_event = event_getFromLua(L);
282 cur_event->save = b;
283 return 0;
284 }
285
286
287 /**
288 * @brief Tries to claim systems or strings.
289 *
290 * Claiming systems and strings is a way to avoid mission collisions preemptively.
291 *
292 * Note it does not actually perform the claim if it fails to claim. It also
293 * does not work more than once.
294 *
295 * @usage if not evt.claim( { system.get("Gamma Polaris") } ) then evt.finish( false ) end
296 * @usage if not evt.claim( system.get("Gamma Polaris") ) then evt.finish( false ) end
297 * @usage if not evt.claim( 'some_string' ) then evt.finish( false ) end
298 * @usage if not evt.claim( { system.get("Gamma Polaris"), 'some_string' } ) then evt.finish( false ) end
299 *
300 * @luatparam System|String|{System,String...} params Table of systems/strings to claim or a single system/string.
301 * @luatreturn boolean true if was able to claim, false otherwise.
302 * @luafunc claim( params )
303 */
evt_claim(lua_State * L)304 static int evt_claim( lua_State *L )
305 {
306 Claim_t *claim;
307 Event_t *cur_event;
308
309 /* Get current event. */
310 cur_event = event_getFromLua(L);
311
312 /* Check to see if already claimed. */
313 if (cur_event->claims != NULL) {
314 NLUA_ERROR(L, "Event trying to claim but already has.");
315 return 0;
316 }
317
318 /* Create the claim. */
319 claim = claim_create();
320
321 /* Handle parameters. */
322 if (lua_istable(L,1)) {
323 /* Iterate over table. */
324 lua_pushnil(L);
325 while (lua_next(L, 1) != 0) {
326 if (lua_issystem(L,-1))
327 claim_addSys( claim, lua_tosystem( L, -1 ) );
328 else if (lua_isstring(L,-1))
329 claim_addStr( claim, lua_tostring( L, -1 ) );
330 lua_pop(L,1);
331 }
332 }
333 else if (lua_issystem(L, 1))
334 claim_addSys( claim, lua_tosystem( L, 1 ) );
335 else if (lua_isstring(L, 1))
336 claim_addStr( claim, lua_tostring( L, 1 ) );
337 else
338 NLUA_INVALID_PARAMETER(L);
339
340 /* Test claim. */
341 if (claim_test( claim )) {
342 claim_destroy( claim );
343 lua_pushboolean(L,0);
344 return 1;
345 }
346
347 /* Set the claim. */
348 cur_event->claims = claim;
349 claim_activate( claim );
350 lua_pushboolean(L,1);
351 return 1;
352 }
353
354