// BLANKART //----------------------------------------------------------------------------- // Copyright (C) 2025 by BlanKart Team. // Copyright (C) 2014-2025 by Sonic Team Junior. // Copyright (C) 2016 by John "JTE" Muniz. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file lua_itemlib.c /// \brief item structures library for Lua scripting #include "doomdef.h" #include "k_items.h" #include "lua_script.h" #include "lua_libs.h" #include "lua_hud.h" // hud_running errors #include "lua_hook.h" // hook_cmd_running errors enum itemvars { itemvars_equipstyle, itemvars_equipstylealt, itemvars_flags, itemvars_flagsalt, //itemvars_graphics, // see K_GetItemGraphics itemvars_altcvar, itemvars_altenabled, }; static const char *const itemvars_opt[] = { "equipstyle", "equipstylealt", "flags", "flagsalt", //"graphics", "altcvar", "altenabled", NULL }; static int item_get(lua_State *L) { kartitem_t *item = *((kartitem_t**)luaL_checkudata(L, 1, META_KARTITEM)); enum itemvars field = luaL_checkoption(L, 2, NULL, itemvars_opt); // items are always valid, only added, never removed I_Assert(item != NULL); switch (field) { case itemvars_equipstyle: lua_pushinteger(L, item->equipstyle[0]); break; case itemvars_equipstylealt: lua_pushinteger(L, item->equipstyle[1]); break; case itemvars_flags: lua_pushinteger(L, item->flags[0]); break; case itemvars_flagsalt: lua_pushinteger(L, item->flags[1]); break; case itemvars_altcvar: LUA_PushUserdata(L, item->altcvar, META_CVAR); break; case itemvars_altenabled: lua_pushboolean(L, item->altenabled); break; default: return luaL_error(L, LUA_QL("kartitem_t") " has no field named " LUA_QS, itemvars_opt[field]); } return 1; } static int item_set(lua_State *L) { return luaL_error(L, LUA_QL("kartitem_t") " struct cannot be edited by Lua."); } static int item_num(lua_State *L) { kartitem_t *item = *((kartitem_t**)luaL_checkudata(L, 1, META_KARTITEM)); // items are always valid, only added, never removed I_Assert(item != NULL); lua_pushinteger(L, item - kartitems); return 1; } enum resultvars { resultvars_type, resultvars_amount, resultvars_displayname, resultvars_isalt, resultvars_flags, //resultvars_odds, //resultvars_uniqueodds, resultvars_basecooldown, resultvars_cooldown, }; static const char *const resultvars_opt[] = { "type", "amount", "displayname", "isalt", "flags", //"odds", //"uniqueodds", "basecooldown", "cooldown", NULL }; static int result_get(lua_State *L) { kartresult_t *result = *((kartresult_t**)luaL_checkudata(L, 1, META_KARTRESULT)); enum resultvars field = luaL_checkoption(L, 2, NULL, resultvars_opt); // results are always valid, only added, never removed I_Assert(result != NULL); switch (field) { case resultvars_type: lua_pushinteger(L, result->type); break; case resultvars_amount: lua_pushinteger(L, result->amount); break; case resultvars_displayname: lua_pushstring(L, result->displayname); break; case resultvars_isalt: lua_pushboolean(L, result->isalt); break; case resultvars_flags: lua_pushinteger(L, result->flags); break; //case resultvars_odds: //i don't have time for this shit //break; //case resultvars_uniqueodds: //break; case resultvars_basecooldown: lua_pushinteger(L, result->basecooldown); break; case resultvars_cooldown: lua_pushinteger(L, result->cooldown); break; default: return luaL_error(L, LUA_QL("kartresult_t") " has no field named " LUA_QS, resultvars_opt[field]); } return 1; } static int result_set(lua_State *L) { kartresult_t *result = *((kartresult_t**)luaL_checkudata(L, 1, META_KARTRESULT)); enum resultvars field = luaL_checkoption(L, 2, NULL, resultvars_opt); if (hud_running) return luaL_error(L, "Do not alter kartresult_t in HUD rendering code!"); if (hook_cmd_running) return luaL_error(L, "Do not alter kartresult_t in BuildCMD code!"); // results are always valid, only added, never removed I_Assert(result != NULL); switch (field) { case resultvars_type: case resultvars_amount: case resultvars_displayname: case resultvars_isalt: case resultvars_flags: case resultvars_basecooldown: return luaL_error(L, LUA_QL("kartresult_t") " field " LUA_QS " should not be set directly.", resultvars_opt[field]); case resultvars_cooldown: result->cooldown = luaL_checkinteger(L, 3); break; default: return luaL_error(L, LUA_QL("kartresult_t") " has no field named " LUA_QS, resultvars_opt[field]); } return 0; } static int result_num(lua_State *L) { kartresult_t *result = *((kartresult_t**)luaL_checkudata(L, 1, META_KARTRESULT)); // results are always valid, only added, never removed I_Assert(result != NULL); lua_pushinteger(L, result - kartresults); return 1; } static int graphics_get(lua_State *L) { kartitemgraphics_t *graphics = *((kartitemgraphics_t**)luaL_checkudata(L, 1, META_KARTITEMGRAPHICS)); INT32 index = luaL_checkinteger(L, 2); if (index < 0 || index >= graphics->numpatches) return luaL_error(L, "patch index %d out of range (0 - %d)", index, graphics->numpatches-1); LUA_PushUserdata(L, graphics->patches[index], META_PATCH); return 1; } static int graphics_set(lua_State *L) { return luaL_error(L, LUA_QL("kartitemgraphics_t") " struct cannot be edited by Lua."); } static int graphics_num(lua_State *L) { kartitemgraphics_t *graphics = *((kartitemgraphics_t**)luaL_checkudata(L, 1, META_KARTITEMGRAPHICS)); lua_pushinteger(L, graphics->numpatches); return 1; } static int lib_iterateKartItems(lua_State *L) { INT32 i; if (lua_gettop(L) < 2) { lua_pushcfunction(L, lib_iterateKartItems); return 1; } lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (*(kartitem_t **)luaL_checkudata(L, 1, META_KARTITEM)) - kartitems + 1; else i = 1; if (i >= 1 && i < numkartitems) { LUA_PushUserdata(L, &kartitems[i], META_KARTITEM); return 1; } return 0; } static int lib_iterateKartResults(lua_State *L) { INT32 i; if (lua_gettop(L) < 2) { lua_pushcfunction(L, lib_iterateKartResults); return 1; } lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (*(kartresult_t **)luaL_checkudata(L, 1, META_KARTRESULT)) - kartresults + 1; else i = 0; if (i >= 0 && i < numkartresults) { LUA_PushUserdata(L, &kartresults[i], META_KARTRESULT); return 1; } return 0; } static int lib_getKartItem(lua_State *L) { if (lua_type(L, 2) == LUA_TNUMBER) { INT32 i = luaL_checkinteger(L, 2); if (i < 1 || i >= numkartitems) return luaL_error(L, "kartitem index %d out of range (1 - %d)", i, numkartitems-1); LUA_PushUserdata(L, &kartitems[i], META_KARTITEM); return 1; } const char *field = luaL_checkstring(L, 2); if (fastcmp(field, "iterate")) { lua_pushcfunction(L, lib_iterateKartItems); return 1; } return 0; } static int lib_numKartItems(lua_State *L) { lua_pushinteger(L, numkartitems); return 1; } static int lib_getKartResult(lua_State *L) { if (lua_type(L, 2) == LUA_TNUMBER) { INT32 i = luaL_checkinteger(L, 2); if (i < 0 || i >= numkartresults) return luaL_error(L, "kartresult index %d out of range (0 - %d)", i, numkartresults-1); LUA_PushUserdata(L, &kartresults[i], META_KARTRESULT); return 1; } const char *field = luaL_checkstring(L, 2); if (fastcmp(field, "iterate")) { lua_pushcfunction(L, lib_iterateKartResults); return 1; } return 0; } static int lib_numKartResults(lua_State *L) { lua_pushinteger(L, numkartresults); return 1; } int LUA_ItemLib(lua_State *L) { luaL_newmetatable(L, META_KARTITEM); lua_pushcfunction(L, item_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, item_set); lua_setfield(L, -2, "__newindex"); lua_pushcfunction(L, item_num); lua_setfield(L, -2, "__len"); lua_pop(L, 1); luaL_newmetatable(L, META_KARTRESULT); lua_pushcfunction(L, result_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, result_set); lua_setfield(L, -2, "__newindex"); lua_pushcfunction(L, result_num); lua_setfield(L, -2, "__len"); lua_pop(L, 1); luaL_newmetatable(L, META_KARTITEMGRAPHICS); lua_pushcfunction(L, graphics_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, graphics_set); lua_setfield(L, -2, "__newindex"); lua_pushcfunction(L, graphics_num); lua_setfield(L, -2, "__len"); lua_pop(L, 1); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getKartItem); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, lib_numKartItems); lua_setfield(L, -2, "__len"); lua_setmetatable(L, -2); lua_setglobal(L, "kartitems"); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getKartResult); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, lib_numKartResults); lua_setfield(L, -2, "__len"); lua_setmetatable(L, -2); lua_setglobal(L, "kartresults"); return 0; }