int luaX_script_unload(lua_State *L) { const char *file = luaL_checkstring(L, 1); luna_script *result; luna_state *state = api_getstate(L); result = list_find(state->scripts, file, &script_cmp); if (!result) { return luaL_error(L, "script '%s' not loaded", file); } else { luna_script script = *result; if (script.state == L) return luaL_error(L, "cannot unload self"); if (!script_unload(state, file)) return luaX_push_scriptinfo(L, &script); else return luaL_error(L, "failed to load script '%s'", file); } return 0; }
/* * Loads (or reloads) the Script created in the given Lua stack. * * Assume a Script definition table (table_ref) has the form of * { 'module' [, arg1 [, ... [, argn]]] } * * The module is `required' and then the function `new` is called on the table * that is returned from `require`. The args supplied in the script definition * are passed into the `new` function. * * Returns 0 if successful, 1 if an error occurs. If an error occurs, an error * string is pushed onto A. */ int script_load (Script *script, lua_State *A) { const char *module_name; const int table_index = lua_gettop(A) + 1; /* we push it onto the stack */ int args, ret = 1; if (script->is_loaded) script_unload(script, A); lua_rawgeti(A, LUA_REGISTRYINDEX, script->table_ref); /* module = require 'module_name' */ lua_getglobal(A, "require"); utils_push_table_head(A, table_index); module_name = lua_tostring(A, -1); if (lua_pcall(A, 1, 1, 0)) { lua_pushfstring(A, "Cannot load module `%s': %s", module_name, lua_tostring(A, -1)); /* push error message beneath pcall error and table */ lua_insert(A, lua_gettop(A) - 2); lua_pop(A, 2); /* pcall error and table */ goto exit; } /* object = module.new(...) */ lua_getfield(A, -1, "new"); if (!lua_isfunction(A, -1)) { lua_pop(A, 3); /* 'new', item returned by `require`, and table */ lua_pushfstring(A, "Cannot load module `%s': `new' is not a function!", module_name); goto exit; } args = utils_push_table_data(A, table_index); if (lua_pcall(A, args, 1, 0)) { lua_pop(A, 2); /* pcall error, item returned by `require`, and table */ lua_pushfstring(A, "Cannot load module `%s': call to `new` failed with args", module_name); goto exit; } script->object_ref = luaL_ref(A, LUA_REGISTRYINDEX); script->is_loaded = 1; ret = 0; lua_pop(A, 2); /* table returned from require and definition table */ exit: script->be_loaded = 0; return ret; }
/* * Sends a Message to the object created from script_load. * * Assumes a message definition table at -1 in the form of * { 'message' [, arg1 [, ... [, argn]]], author} * * The 'message' is some method of the instantiated object which was created in * script_load. If it doesn't exist it actually isn't an error. This is one of * those "it's a feature, not a bug" things -- by willing to say this isn't an * error we gain the ability to very easily add new message primitives (the * methods themselves) to the system. * * Returns 0 if successful, 1 if an error occurs. If an error occurs, an error * string is pushed onto A. */ int script_send (Script *script, lua_State *A) { const int message_index = lua_gettop(A); const int object_index = message_index + 1; const char *message = NULL; int args = 0; int ret = 1; /* * object[message_title]:(arg1, arg2, ..., argN) */ lua_rawgeti(A, LUA_REGISTRYINDEX, script->object_ref); utils_push_table_head(A, message_index); message = lua_tostring(A, -1); lua_gettable(A, -2); /* it's not an error if the function doesn't exist */ if (!lua_isfunction(A, -1)) { lua_pop(A, 2); /* whatever isn't a function and the object_ref */ goto success; } /* push `self' reference and tail of message which includes the author. */ lua_pushvalue(A, object_index); args = utils_push_table_data(A, message_index); if (lua_pcall(A, args + 1, 0, 0)) { /* TODO: Figure out why the 'Cannot send message' isn't appearing */ lua_pushfstring(A, "Cannot send message `%s': %s", message, lua_tostring(A, -1)); /* push error message beneath pcall error and object_ref */ lua_insert(A, lua_gettop(A) - 2); lua_pop(A, 2); /* pcall error and object_ref */ /* unload after the object has been popped or it won't gc */ script_unload(script, A); goto exit; } lua_pop(A, 1); /* object_ref */ success: ret = 0; exit: return ret; }
/** * Analyze /cmd type commands the player has typed in the console or bound to a key. * Sort out the "client intern" commands and expand or pre process them for the server. * @param cmd Command to check * @return 0 to send command to server, 1 to not send it */ int client_command_check(char *cmd) { if (!strncasecmp(cmd, "/ready_spell", 12)) { cmd = strchr(cmd, ' '); if (!cmd || *++cmd == 0) { draw_info("Usage: /ready_spell <spell name>", COLOR_GREEN); } else { int i, ii; for (i = 0; i < SPELL_LIST_MAX; i++) { for (ii = 0; ii < DIALOG_LIST_ENTRY; ii++) { if (spell_list[i].entry[0][ii].flag >= LIST_ENTRY_USED) { if (!strcmp(spell_list[i].entry[0][ii].name, cmd)) { if (spell_list[i].entry[0][ii].flag == LIST_ENTRY_KNOWN) { fire_mode_tab[FIRE_MODE_SPELL].spell = &spell_list[i].entry[0][ii]; RangeFireMode = FIRE_MODE_SPELL; sound_play_effect("scroll.ogg", MENU_SOUND_VOL); draw_info("Spell ready.", COLOR_GREEN); return 1; } } } if (spell_list[i].entry[1][ii].flag >= LIST_ENTRY_USED) { if (!strcmp(spell_list[i].entry[1][ii].name, cmd)) { if (spell_list[i].entry[1][ii].flag==LIST_ENTRY_KNOWN) { fire_mode_tab[FIRE_MODE_SPELL].spell = &spell_list[i].entry[1][ii]; RangeFireMode = FIRE_MODE_SPELL; sound_play_effect("scroll.ogg", MENU_SOUND_VOL); draw_info("Spell ready.", COLOR_GREEN); return 1; } } } } } } draw_info("Unknown spell.", COLOR_GREEN); return 1; } else if (!strncasecmp(cmd, "/pray", 5)) { /* Give out "You are at full grace." when needed - * server will not send us anything when this happens */ if (cpl.stats.grace == cpl.stats.maxgrace) draw_info("You are at full grace. You stop praying.", COLOR_WHITE); } else if (!strncasecmp(cmd, "/keybind", 8)) { map_udate_flag = 2; if (cpl.menustatus != MENU_KEYBIND) { keybind_status = KEYBIND_STATUS_NO; cpl.menustatus = MENU_KEYBIND; } else { save_keybind_file(KEYBIND_FILE); cpl.menustatus = MENU_NO; } sound_play_effect("scroll.ogg", 100); reset_keys(); return 1; } else if (!strncmp(cmd, "/target", 7)) { /* Logic is: if first parameter char is a digit, is enemy, friend or self. * If first char a character - then it's a name of a living object. */ if (!strncmp(cmd, "/target friend", 14)) strcpy(cmd, "/target 1"); else if (!strncmp(cmd,"/target enemy", 13)) strcpy(cmd, "/target 0"); else if (!strncmp(cmd, "/target self", 12)) strcpy(cmd, "/target 2"); } else if (!strncmp(cmd, "/help", 5)) { cmd += 5; if (cmd == NULL || strcmp(cmd, "") == 0) show_help("main"); else show_help(cmd + 1); return 1; } else if (!strncmp(cmd, "/script ", 8)) { cmd += 8; if (!strncmp(cmd, "load ", 5)) { cmd += 5; script_load(cmd); } if (!strncmp(cmd, "unload ", 7)) { cmd += 7; script_unload(cmd); } else if (!strncmp(cmd, "list", 4)) { script_list(); } else if (!strncmp(cmd, "send ", 5)) { cmd += 5; script_send(cmd); } return 1; } else if (!strncmp(cmd, "/shop", 5)) { if (!shop_gui) { initialize_shop(SHOP_STATE_NONE); } else { draw_info("You must close the shop window before trying to set up another shop.", COLOR_RED); } return 1; } else if (!strncmp(cmd, "/ignore", 7)) { ignore_command(cmd + 7); return 1; } else if (!strncmp(cmd, "/reply", 6)) { cmd = strchr(cmd, ' '); if (!cmd || *++cmd == '\0') { draw_info("Usage: /reply <message>", COLOR_RED); } else { if (!cpl.player_reply[0]) { draw_info("There is no one you can /reply.", COLOR_RED); } else { char buf[2048]; snprintf(buf, sizeof(buf), "/tell %s %s", cpl.player_reply, cmd); send_command(buf); } } return 1; } else if (!strncmp(cmd, "/resetwidgets", 13)) { reset_widget(NULL); return 1; } else if (!strncmp(cmd, "/resetwidget", 12)) { cmd = strchr(cmd, ' '); if (!cmd || *++cmd == '\0') { draw_info("Usage: /resetwidget <name>", COLOR_RED); } else { reset_widget(cmd); } return 1; } return 0; }