// DR. ROBOTNIK'S RING RACERS //----------------------------------------------------------------------------- // Copyright (C) 2024 by Kart Krew. // Copyright (C) 2020 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_botvarslib.c /// \brief player botvars structure library for Lua scripting #include "doomdef.h" #include "fastcmp.h" #include "lua_script.h" #include "lua_libs.h" #include "k_bot.h" enum botvars { botvars_valid = 0, botvars_style, botvars_difficulty, botvars_diffincrease, botvars_rival, botvars_rubberband, }; static const char *const botvars_opt[] = { "valid", "style", "difficulty", "diffincrease", "rival", "rubberband", NULL }; #define UNIMPLEMENTED luaL_error(L, LUA_QL("botvars_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", follower_opt[field]) static int botvars_get(lua_State *L) { botvars_t *botvars = *((botvars_t **)luaL_checkudata(L, 1, META_BOTVARS)); enum botvars field = luaL_checkoption(L, 2, NULL, botvars_opt); // This is a property that always exists in a player. I_Assert(botvars != NULL); switch (field) { case botvars_valid: lua_pushboolean(L, botvars != NULL); break; case botvars_style: lua_pushinteger(L, botvars->style); break; case botvars_difficulty: lua_pushinteger(L, botvars->difficulty); break; case botvars_diffincrease: lua_pushinteger(L, botvars->diffincrease); break; case botvars_rival: lua_pushboolean(L, botvars->rival); break; case botvars_rubberband: lua_pushfixed(L, botvars->rubberband); break; } return 1; } #define NOSET luaL_error(L, LUA_QL("botvars_t") " field " LUA_QS " should not be set directly.", botvars_opt[field]) static int botvars_set(lua_State *L) { botvars_t *botvars = *((botvars_t **)luaL_checkudata(L, 1, META_BOTVARS)); enum botvars field = luaL_checkoption(L, 2, botvars_opt[0], botvars_opt); // This is a property that always exists in a player. I_Assert(botvars != NULL); INLEVEL switch(field) { case botvars_valid: return NOSET; case botvars_style: botvars->style = luaL_checkinteger(L, 3); break; case botvars_difficulty: botvars->difficulty = luaL_checkinteger(L, 3); break; case botvars_diffincrease: botvars->diffincrease = luaL_checkinteger(L, 3); break; case botvars_rival: botvars->rival = luaL_checkboolean(L, 3); break; case botvars_rubberband: botvars->rubberband = luaL_checkfixed(L, 3); break; } return 0; } #undef NOSET enum botdata { botdata_valid, botdata_itemdelay, botdata_itemconfirm, botdata_turnconfirm, botdata_respawnconfirm, botdata_driftstate, botdata_driftturn, botdata_drifttime, botdata_driftlockout, botdata_driftmaxdist, botdata_driftpowerdiv, botdata_driftstatedelay, botdata_driftskill, botdata_acceldown, botdata_brakedown, botdata_driftdown, botdata_itemdown, botdata_dolookback, botdata_itemwasdown, botdata_itemthrow, botdata_turnamt, }; static const char *const botdata_opt[] = { "valid", "itemdelay", "itemconfirm", "turnconfirm", "respawnconfirm", "driftstate", "driftturn", "drifttime", "driftlockout", "driftmaxdist", "driftpowerdiv", "driftstatedelay", "driftskill", "acceldown", "brakedown", "driftdown", "itemdown", "dolookback", "itemwasdown", "itemthrow", "turnamt", NULL }; static int botdata_get(lua_State *L) { botdata_t *botdata = *((botdata_t **)luaL_checkudata(L, 1, META_BOTDATA)); enum botdata field = luaL_checkoption(L, 2, NULL, botdata_opt); // it's a static array... i think... I_Assert(botdata != NULL); switch (field) { case botdata_valid: lua_pushboolean(L, botdata != NULL); break; case botdata_itemdelay: lua_pushinteger(L, botdata->itemdelay); break; case botdata_itemconfirm: lua_pushinteger(L, botdata->itemconfirm); break; case botdata_turnconfirm: lua_pushinteger(L, botdata->turnconfirm); break; case botdata_respawnconfirm: lua_pushinteger(L, botdata->respawnconfirm); break; case botdata_driftstate: lua_pushinteger(L, botdata->driftstate); break; case botdata_driftturn: lua_pushinteger(L, botdata->driftturn); break; case botdata_drifttime: lua_pushinteger(L, botdata->drifttime); break; case botdata_driftlockout: lua_pushinteger(L, botdata->driftlockout); break; case botdata_driftmaxdist: lua_pushinteger(L, botdata->driftmaxdist); break; case botdata_driftpowerdiv: lua_pushinteger(L, botdata->driftpowerdiv); break; case botdata_driftstatedelay: lua_pushinteger(L, botdata->driftstatedelay); break; case botdata_driftskill: lua_pushfixed(L, botdata->driftskill); break; case botdata_acceldown: lua_pushboolean(L, botdata->acceldown); break; case botdata_brakedown: lua_pushboolean(L, botdata->brakedown); break; case botdata_driftdown: lua_pushboolean(L, botdata->driftdown); break; case botdata_itemdown: lua_pushboolean(L, botdata->itemdown); break; case botdata_dolookback: lua_pushboolean(L, botdata->dolookback); break; case botdata_itemwasdown: lua_pushboolean(L, botdata->itemwasdown); break; case botdata_itemthrow: lua_pushinteger(L, botdata->itemthrow); break; case botdata_turnamt: lua_pushinteger(L, botdata->turnamt); break; } return 1; } #define NOSET luaL_error(L, LUA_QL("botdata_t") " field " LUA_QS " should not be set directly.", botdata_opt[field]) static int botdata_set(lua_State *L) { botdata_t *botdata = *((botdata_t **)luaL_checkudata(L, 1, META_BOTDATA)); enum botdata field = luaL_checkoption(L, 2, NULL, botdata_opt); I_Assert(botdata != NULL); switch (field) { case botdata_valid: return NOSET; case botdata_itemdelay: botdata->itemdelay = luaL_checkinteger(L, 3); break; case botdata_itemconfirm: botdata->itemconfirm = luaL_checkinteger(L, 3); break; case botdata_turnconfirm: botdata->turnconfirm = luaL_checkinteger(L, 3); break; case botdata_respawnconfirm: botdata->respawnconfirm = luaL_checkinteger(L, 3); break; case botdata_driftstate: botdata->driftstate = luaL_checkinteger(L, 3); break; case botdata_driftturn: botdata->driftturn = luaL_checkinteger(L, 3); break; case botdata_drifttime: botdata->drifttime = luaL_checkinteger(L, 3); break; case botdata_driftlockout: botdata->driftlockout = luaL_checkinteger(L, 3); break; case botdata_driftmaxdist: botdata->driftmaxdist = luaL_checkinteger(L, 3); break; case botdata_driftpowerdiv: botdata->driftpowerdiv = luaL_checkinteger(L, 3); break; case botdata_driftstatedelay: botdata->driftstatedelay = luaL_checkinteger(L, 3); break; case botdata_driftskill: botdata->driftskill = luaL_checkfixed(L, 3); break; case botdata_acceldown: botdata->acceldown = luaL_checkboolean(L, 3); break; case botdata_brakedown: botdata->brakedown = luaL_checkboolean(L, 3); break; case botdata_driftdown: botdata->driftdown = luaL_checkboolean(L, 3); break; case botdata_itemdown: botdata->itemdown = luaL_checkboolean(L, 3); break; case botdata_dolookback: botdata->dolookback = luaL_checkboolean(L, 3); break; case botdata_itemwasdown: botdata->itemwasdown = luaL_checkboolean(L, 3); break; case botdata_itemthrow: botdata->itemthrow = luaL_checkinteger(L, 3); break; case botdata_turnamt: botdata->turnamt = luaL_checkinteger(L, 3); break; } return 0; } #undef NOSET static int lib_iterateBotData(lua_State *L) { INT32 i; if (lua_gettop(L) < 2) { lua_pushcfunction(L, lib_iterateBotData); return 1; } lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (INT32)(*((botdata_t **)luaL_checkudata(L, 1, META_BOTDATA)) - K_GetBotData(0)) + 1; else i = 0; if (i < MAXPLAYERS) { LUA_PushUserdata(L, K_GetBotData(i), META_BOTDATA); return 1; } return 0; } static int lib_getBotData(lua_State *L) { INT32 i; if (lua_type(L, 2) == LUA_TNUMBER) { i = luaL_checkinteger(L, 2); if (i < 0 || i >= MAXPLAYERS) return luaL_error(L, "botdata[] index %d out of range (0 - %d)", i, MAXPLAYERS-1); LUA_PushUserdata(L, K_GetBotData(i), META_BOTDATA); return 1; } if (fastcmp(luaL_checkstring(L, 2), "iterate")) { lua_pushcfunction(L, lib_iterateBotData); return 1; } return 0; } static int lib_numBotData(lua_State *L) { lua_pushinteger(L, MAXPLAYERS); return 1; } int LUA_BotVarsLib(lua_State *L) { luaL_newmetatable(L, META_BOTVARS); lua_pushcfunction(L, botvars_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, botvars_set); lua_setfield(L, -2, "__newindex"); lua_pop(L,1); luaL_newmetatable(L, META_BOTDATA); lua_pushcfunction(L, botdata_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, botdata_set); lua_setfield(L, -2, "__newindex"); lua_pop(L,1); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getBotData); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, lib_numBotData); lua_setfield(L, -2, "__len"); lua_setmetatable(L, -2); lua_setglobal(L, "botdata"); return 0; }