1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
14 /**
15  * @file common/script_lua.c
16  *
17  */
18 
19 #ifndef WIN32
20 #include <ctype.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/wait.h>
25 #include <signal.h>
26 #endif
27 
28 #include "client.h"
29 
30 #ifdef HAVE_LUA
31 /* It seems easier to just comment everything out if we don't have
32  * lua vs trying to play around with it in the makefiles.
33  */
34 
35 #include <external.h>
36 #include <script_lua.h>
37 #include <lua.h>
38 #include <lualib.h>
39 
40 #if LUA_VERSION_NUM >= 501
41 #include <lauxlib.h>
42 #endif
43 
44 struct script_state {
45     lua_State* state;
46     const char* filename;
47 };
48 
49 #if 0
50 static void *l_alloc (void * /*ud*/, void *ptr, size_t /*osize*/, size_t nsize)
51 {
52     if (nsize == 0) {
53         free(ptr);
54         return NULL;
55     } else {
56         return g_realloc(ptr, nsize);
57     }
58 }
59 #endif
60 
l_readerfile(lua_State * L,void * data,size_t * size)61 static const char* l_readerfile(lua_State *L, void *data, size_t *size)
62 {
63     static char buf[4096];
64     FILE* file = (FILE*)data;
65     *size = fread(buf, 1, 4096, file);
66     if ( !*size && ferror(file) ) {
67         return NULL;
68     }
69     if ( !*size && feof(file)) {
70         return NULL;
71     }
72     return buf;
73 }
74 
75 static struct script_state* scripts = NULL;
76 static int script_count = 0;
77 
update_player(lua_State * lua)78 static void update_player(lua_State* lua)
79 {
80     lua_pushstring(lua, "player");
81     lua_gettable(lua, LUA_GLOBALSINDEX);
82     if (!lua_istable(lua, -1)) {
83         lua_pop(lua, 1);
84         return;
85     }
86 
87     lua_pushstring(lua, "hp");
88     lua_pushnumber(lua, cpl.stats.hp);
89     lua_settable(lua, -3);
90     lua_pushstring(lua, "gr");
91     lua_pushnumber(lua, cpl.stats.grace);
92     lua_settable(lua, -3);
93     lua_pushstring(lua, "sp");
94     lua_pushnumber(lua, cpl.stats.sp);
95     lua_settable(lua, -3);
96     lua_pushstring(lua, "food");
97     lua_pushnumber(lua, cpl.stats.food);
98     lua_settable(lua, -3);
99 
100     lua_pop(lua, 1);
101 }
102 
do_item(lua_State * lua,item * it)103 static void do_item(lua_State* lua, item* it)
104 {
105     lua_newtable(lua);
106     lua_pushstring(lua, "s_name");
107     lua_pushstring(lua, it->s_name);
108     lua_settable(lua, -3);
109     lua_pushstring(lua, "magical");
110     lua_pushnumber(lua, it->magical);
111     lua_settable(lua, -3);
112     lua_pushstring(lua, "cursed");
113     lua_pushnumber(lua, it->cursed);
114     lua_settable(lua, -3);
115     lua_pushstring(lua, "damned");
116     lua_pushnumber(lua, it->damned);
117     lua_settable(lua, -3);
118     lua_pushstring(lua, "unpaid");
119     lua_pushnumber(lua, it->unpaid);
120     lua_settable(lua, -3);
121     lua_pushstring(lua, "locked");
122     lua_pushnumber(lua, it->locked);
123     lua_settable(lua, -3);
124     lua_pushstring(lua, "applied");
125     lua_pushnumber(lua, it->applied);
126     lua_settable(lua, -3);
127     lua_pushstring(lua, "open");
128     lua_pushnumber(lua, it->open);
129     lua_settable(lua, -3);
130 }
131 
update_inv(lua_State * lua)132 static void update_inv(lua_State* lua)
133 {
134     item* it;
135     int index = 1;
136     lua_pushstring(lua, "inv");
137     lua_newtable(lua);
138     lua_settable(lua, LUA_GLOBALSINDEX);
139     lua_pushstring(lua, "inv");
140     lua_gettable(lua, LUA_GLOBALSINDEX);
141 
142     for ( it = cpl.ob->inv; it; it = it->next ) {
143         lua_pushnumber(lua, index++);
144         do_item(lua, it);
145         lua_settable(lua, -3);
146     }
147     lua_pop(lua, 1);
148 }
149 
update_ground(lua_State * lua)150 static void update_ground(lua_State* lua)
151 {
152     item* it;
153     int index = 1;
154     lua_pushstring(lua, "ground");
155     lua_newtable(lua);
156     lua_settable(lua, LUA_GLOBALSINDEX);
157     lua_pushstring(lua, "ground");
158     lua_gettable(lua, LUA_GLOBALSINDEX);
159 
160     for ( it = cpl.below->inv; it; it = it->next ) {
161         if ( it->tag == 0 || strlen(it->s_name) == 0 ) {
162             continue;
163         }
164 
165         lua_pushnumber(lua, index++);
166 
167         do_item(lua, it);
168         lua_settable(lua, -3);
169     }
170     lua_pop(lua, 1);
171 }
172 
173 
lua_draw(lua_State * L)174 static int lua_draw(lua_State *L)
175 {
176     int n = lua_gettop(L);    /* number of arguments */
177     const char* what;
178     if ( n != 1 ) {
179         lua_pushstring(L, "draw what?");
180         lua_error(L);
181     }
182     if ( !lua_isstring(L, 1) ) {
183         lua_pushstring(L, "expected a string");
184         lua_error(L);
185     }
186 
187     what = lua_tostring(L,1);
188     draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, what);
189 
190     return 0;
191 }
192 
lua_issue(lua_State * L)193 static int lua_issue(lua_State *L)
194 {
195     int n = lua_gettop(L);    /* number of arguments */
196     const char* what;
197     int repeat, must_send;
198     if ( n != 3 ) {
199         lua_pushstring(L, "syntax is cfissue repeat must_send command");
200         lua_error(L);
201     }
202     if ( !lua_isnumber(L, 1) ) {
203         lua_pushstring(L, "expected a number");
204         lua_error(L);
205     }
206 
207     if ( !lua_isnumber(L, 2) ) {
208         lua_pushstring(L, "expected a number");
209         lua_error(L);
210     }
211 
212     if ( !lua_isstring(L, 3) ) {
213         lua_pushstring(L, "expected a number");
214         lua_error(L);
215     }
216 
217     repeat = lua_tonumber(L, 1);
218     must_send = lua_tonumber(L, 2);
219     what = lua_tostring(L,3);
220     send_command(what,repeat,must_send);
221 
222     return 0;
223 }
224 
script_lua_load(const char * name)225 void script_lua_load(const char* name)
226 {
227     lua_State* lua;
228     FILE* file;
229     int load;
230     int index = script_count;
231 
232     file = fopen(name,"r");
233     if ( !file ) {
234         draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
235                       "Invalid file");
236         return;
237     }
238 
239     lua = lua_open();
240     if ( !lua ) {
241         draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
242                       "Memory allocation error.");
243         fclose(file);
244         return;
245     }
246     luaopen_base(lua);
247     lua_pop(lua,1);
248     luaopen_table(lua);
249     lua_pop(lua,1);
250 
251     if (( load = lua_load(lua, l_readerfile, (void*)file, name))) {
252         draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
253                       "Load error!");
254         if ( load == LUA_ERRSYNTAX )
255             draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
256                           "Syntax error!");
257         fclose(file);
258         lua_close(lua);
259         return;
260     }
261     fclose(file);
262 
263     lua_register(lua, "cfdraw", lua_draw);
264     lua_register(lua, "cfissue", lua_issue);
265 
266     lua_pushstring(lua, "player");
267     lua_newtable(lua);
268     lua_settable(lua, LUA_GLOBALSINDEX);
269     update_player(lua);
270     update_inv(lua);
271     update_ground(lua);
272 
273     /* Load functions, init script */
274     if (lua_pcall(lua, 0, 0, 0)) {
275         draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
276                       "Init error!");
277         lua_close(lua);
278         return;
279     }
280 
281     scripts = g_realloc(scripts,sizeof(scripts[0])*(script_count+1));
282 
283     if (scripts == NULL) {
284         LOG(LOG_ERROR, "script_lua_load",
285                 "Could not allocate memory: %s", strerror(errno));
286         exit(EXIT_FAILURE);
287     }
288 
289     script_count++;
290     scripts[index].filename = g_strdup(name);
291     scripts[index].state = lua;
292 
293     /*
294     printf("lua_gettop = %d, lua_type => %s\n", lua_gettop(lua), lua_typename( lua, lua_type(lua, lua_gettop(lua))));
295     printf("lua_gettop = %d, lua_type => %s\n", lua_gettop(lua), lua_typename( lua, lua_type(lua, lua_gettop(lua))));
296     lua_pushstring(lua, "init");
297     printf("lua_gettop = %d, lua_type => %s\n", lua_gettop(lua), lua_typename( lua, lua_type(lua, lua_gettop(lua))));
298     lua_gettable(lua, LUA_GLOBALSINDEX);
299     printf("lua_gettop = %d, lua_type => %s\n", lua_gettop(lua), lua_typename( lua, lua_type(lua, lua_gettop(lua))));
300     if (lua_isfunction(lua, lua_gettop(lua)))
301         lua_call(lua, 0, 0);
302     lua_pop(lua, 1);
303     */
304 }
305 
script_lua_list(const char * param)306 void script_lua_list(const char* param)
307 {
308     if ( script_count == 0 ) {
309         draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
310                       "No LUA scripts are currently running");
311     } else {
312         int i;
313         char buf[1024];
314 
315         snprintf(buf, sizeof(buf), "%d LUA scripts currently running:",script_count);
316         draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf);
317         for ( i=0; i<script_count; ++i) {
318             snprintf(buf, sizeof(buf), "%d %s",i+1,scripts[i].filename);
319             draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf);
320         }
321     }
322 }
323 
script_lua_kill(const char * param)324 void script_lua_kill(const char* param)
325 {
326     int i;
327     i = atoi(param) - 1;
328     if ( i < 0 || i >= script_count ) {
329         draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT,
330                       "Invalid script index!");
331         return;
332     }
333     lua_close(scripts[i].state);
334 
335     if ( i < (script_count-1) ) {
336         memmove(&scripts[i],&scripts[i+1],sizeof(scripts[i])*(script_count-i-1));
337     }
338 
339     --script_count;
340 }
341 
script_lua_stats()342 void script_lua_stats()
343 {
344     int script;
345     lua_State* lua;
346     for ( script = 0; script < script_count; script++ ) {
347         lua = scripts[script].state;
348         lua_pushstring(lua, "event_stats");
349         lua_gettable(lua, LUA_GLOBALSINDEX);
350         if (lua_isfunction(lua, lua_gettop(lua))) {
351             int luaerror;
352             update_player(lua);
353             update_inv(lua);
354             update_ground(lua);
355             if ( ( luaerror = lua_pcall(lua, 0, 0, 0) ) ) {
356                 const char* what = lua_tostring(lua, lua_gettop(lua));
357                 draw_ext_info(
358                     NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, what);
359                 lua_pop(lua,1);
360             }
361         } else {
362             lua_pop(lua, 1);
363         }
364     }
365 }
366 
script_lua_command(const char * command,const char * param)367 int script_lua_command(const char* command, const char* param)
368 {
369     int script;
370     lua_State* lua;
371     int ret = 0;
372     for ( script = 0; script < script_count; script++ ) {
373         lua = scripts[script].state;
374         lua_pushstring(lua, "event_command");
375         lua_gettable(lua, LUA_GLOBALSINDEX);
376         if (lua_isfunction(lua, lua_gettop(lua))) {
377             int luaerror;
378             update_player(lua);
379             update_inv(lua);
380             update_ground(lua);
381             lua_pushstring(lua, command);
382             lua_pushstring(lua, param ? param : "");
383             if ( ( luaerror = lua_pcall(lua, 2, 1, 0) ) ) {
384                 const char* what = lua_tostring(lua, lua_gettop(lua));
385                 draw_ext_info(
386                     NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, what);
387                 lua_pop(lua,1);
388             } else {
389                 ret = lua_tonumber(lua, 1);
390                 lua_pop(lua, 1);
391             }
392         } else {
393             lua_pop(lua, 1);
394         }
395     }
396     return ret;
397 }
398 
399 #endif /* HAVE_LIB_LUA */
400