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