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