From 94f6206c87ea908b287300aced0527e235f2f4b5 Mon Sep 17 00:00:00 2001 From: hayaunderscore Date: Sat, 8 Jun 2024 10:45:36 +0800 Subject: [PATCH] Expose `followers[]` and `follower_t` to lua --- src/Sourcefile | 1 + src/deh_soc.c | 2 +- src/deh_tables.c | 5 + src/doomdef.h | 1 + src/lua_followerlib.c | 272 ++++++++++++++++++++++++++++++++++++++++++ src/lua_libs.h | 5 + src/lua_script.c | 1 + 7 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 src/lua_followerlib.c diff --git a/src/Sourcefile b/src/Sourcefile index 14649b0c7..03bdf7046 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -101,6 +101,7 @@ lua_polyobjlib.c lua_blockmaplib.c lua_hudlib.c lua_hudlib_drawlist.c +lua_followerlib.c k_kart.c k_respawn.c k_collide.c diff --git a/src/deh_soc.c b/src/deh_soc.c index e1507bb64..ebd3e6d93 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3620,7 +3620,7 @@ void readfollower(MYFILE *f) INT32 res; INT32 i; - if (numfollowers > MAXSKINS) + if (numfollowers > MAXFOLLOWERS) { deh_warning("Error: Too many followers, cannot add anymore.\n"); return; diff --git a/src/deh_tables.c b/src/deh_tables.c index 7f960bd2c..ab1661428 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -24,6 +24,7 @@ #include "g_state.h" // gamestate_t (for lua) #include "r_data.h" // patchalphastyle_t #include "k_boss.h" // spottype_t (for lua) +#include "k_follower.h" // followermode_t (for lua) #include "deh_tables.h" @@ -6632,6 +6633,10 @@ struct int_const_s const INT_CONST[] = { {"PRECIPFX_THUNDER",PRECIPFX_THUNDER}, {"PRECIPFX_LIGHTNING",PRECIPFX_LIGHTNING}, {"PRECIPFX_WATERPARTICLES",PRECIPFX_WATERPARTICLES}, + + // followermode_t + {"FOLLOWERMODE_FLOAT",FOLLOWERMODE_FLOAT}, + {"FOLLOWERMODE_GROUND",FOLLOWERMODE_GROUND}, {NULL,0} }; diff --git a/src/doomdef.h b/src/doomdef.h index 1533ed20e..80f717cd6 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -207,6 +207,7 @@ extern char logfilename[1024]; #define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer #define MAXSKINS UINT8_MAX +#define MAXFOLLOWERS UINT16_MAX #define COLORRAMPSIZE 16 #define MAXCOLORNAME 32 diff --git a/src/lua_followerlib.c b/src/lua_followerlib.c new file mode 100644 index 000000000..2bf58dfc3 --- /dev/null +++ b/src/lua_followerlib.c @@ -0,0 +1,272 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// 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_followerlib.c +/// \brief player follower structure library for Lua scripting + +#include "doomdef.h" +#include "fastcmp.h" +#include "k_follower.h" +#include "r_skins.h" +#include "sounds.h" + +#include "lua_script.h" +#include "lua_libs.h" + +enum follower { + follower_valid = 0, + follower_name, + follower_defaultcolor, + follower_mode, + follower_scale, + follower_bubblescale, + follower_atangle, + follower_dist, + follower_height, + follower_zoffs, + follower_horzlag, + follower_vertlag, + follower_anglelag, + follower_bobamp, + follower_bobspeed, + // states + follower_idlestate, + follower_followstate, + follower_hurtstate, + follower_winstate, + follower_losestate, + follower_hitconfirmstate, + follower_hitconfirmtime, + // +}; +static const char *const follower_opt[] = { + "valid", + "name", + "defaultcolor", + "mode", + "scale", + "bubblescale", + "atangle", + "dist", + "height", + "zoffs", + "horzlag", + "vertlag", + "anglelag", + "bobamp", + "bobspeed", + // states + "idlestate", + "followstate", + "hurtstate", + "winstate", + "losestate", + "hitconfirmstate", + "hitconfirmtime", + // + NULL +}; + +#define UNIMPLEMENTED luaL_error(L, LUA_QL("follower_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", follower_opt[field]) + +static int follower_get(lua_State *L) +{ + follower_t *follower = *((follower_t **)luaL_checkudata(L, 1, META_FOLLOWER)); + enum follower field = luaL_checkoption(L, 2, NULL, follower_opt); + + // followers are always valid, only added, never removed + I_Assert(follower != NULL); + + switch (field) + { + case follower_valid: + lua_pushboolean(L, follower != NULL); + break; + case follower_name: + lua_pushstring(L, follower->name); + break; + case follower_defaultcolor: + lua_pushinteger(L, follower->defaultcolor); + break; + case follower_mode: + lua_pushinteger(L, follower->mode); + break; + case follower_scale: + lua_pushfixed(L, follower->scale); + break; + case follower_bubblescale: + lua_pushfixed(L, follower->bubblescale); + break; + case follower_atangle: + lua_pushangle(L, follower->atangle); + break; + case follower_dist: + lua_pushfixed(L, follower->dist); + break; + case follower_height: + lua_pushfixed(L, follower->height); + break; + case follower_zoffs: + lua_pushfixed(L, follower->zoffs); + break; + case follower_horzlag: + lua_pushfixed(L, follower->horzlag); + break; + case follower_vertlag: + lua_pushfixed(L, follower->vertlag); + break; + case follower_anglelag: + lua_pushfixed(L, follower->anglelag); + break; + case follower_bobamp: + lua_pushfixed(L, follower->bobamp); + break; + case follower_bobspeed: + lua_pushinteger(L, follower->bobspeed); + break; + case follower_idlestate: + lua_pushinteger(L, follower->idlestate); + break; + case follower_followstate: + lua_pushinteger(L, follower->followstate); + break; + case follower_hurtstate: + lua_pushinteger(L, follower->hurtstate); + break; + case follower_winstate: + lua_pushinteger(L, follower->winstate); + break; + case follower_losestate: + lua_pushinteger(L, follower->losestate); + break; + case follower_hitconfirmstate: + lua_pushinteger(L, follower->hitconfirmstate); + break; + case follower_hitconfirmtime: + lua_pushinteger(L, follower->hitconfirmtime); + break; + } + return 1; +} + +static int follower_set(lua_State *L) +{ + return luaL_error(L, LUA_QL("follower_t") " struct cannot be edited by Lua."); +} + +static int follower_num(lua_State *L) +{ + follower_t *follower = *((follower_t **)luaL_checkudata(L, 1, META_FOLLOWER)); + + // skins are always valid, only added, never removed + I_Assert(follower != NULL); + + lua_pushinteger(L, follower-followers); + return 1; +} + +static int lib_iterateFollowers(lua_State *L) +{ + INT32 i; + + if (lua_gettop(L) < 2) + { + //return luaL_error(L, "Don't call skins.iterate() directly, use it as 'for skin in skins.iterate do end'."); + lua_pushcfunction(L, lib_iterateFollowers); + return 1; + } + + lua_settop(L, 2); + lua_remove(L, 1); // state is unused. + + if (!lua_isnil(L, 1)) + i = (INT32)(*((follower_t **)luaL_checkudata(L, 1, META_FOLLOWER)) - followers) + 1; + else + i = 0; + + // skins are always valid, only added, never removed + if (i < numfollowers) + { + LUA_PushUserdata(L, &followers[i], META_FOLLOWER); + return 1; + } + + return 0; +} + +static int lib_getFollower(lua_State *L) +{ + const char *field; + INT32 i; + + // find skin by number + if (lua_type(L, 2) == LUA_TNUMBER) + { + i = luaL_checkinteger(L, 2); + // It's kind of funny how the follower limit is 1023 while skins have 255 + if (i < 0 || i >= MAXFOLLOWERS) + return luaL_error(L, "followers[] index %d out of range (0 - %d)", i, MAXFOLLOWERS-1); + if (i >= numfollowers) + return 0; + LUA_PushUserdata(L, &followers[i], META_FOLLOWER); + return 1; + } + + field = luaL_checkstring(L, 2); + + // special function iterate + if (fastcmp(field,"iterate")) + { + lua_pushcfunction(L, lib_iterateFollowers); + return 1; + } + + // find skin by name + i = K_FollowerAvailable(field); + if (i != -1) + { + LUA_PushUserdata(L, &followers[i], META_FOLLOWER); + return 1; + } + + return 0; +} + +static int lib_numFollowers(lua_State *L) +{ + lua_pushinteger(L, numfollowers); + return 1; +} + +int LUA_FollowerLib(lua_State *L) +{ + luaL_newmetatable(L, META_FOLLOWER); + lua_pushcfunction(L, follower_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, follower_set); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, follower_num); + lua_setfield(L, -2, "__len"); + lua_pop(L,1); + + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getFollower); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_numFollowers); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "followers"); + + return 0; +} diff --git a/src/lua_libs.h b/src/lua_libs.h index bc8e4141e..0cc818739 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -90,6 +90,10 @@ extern lua_State *gL; #define META_LUABANKS "LUABANKS[]*" +#define META_ACTIVATOR "ACTIVATOR_T*" + +#define META_FOLLOWER "FOLLOWER_T*" + boolean luaL_checkboolean(lua_State *L, int narg); int LUA_EnumLib(lua_State *L); @@ -108,3 +112,4 @@ int LUA_TagLib(lua_State *L); int LUA_PolyObjLib(lua_State *L); int LUA_BlockmapLib(lua_State *L); int LUA_HudLib(lua_State *L); +int LUA_FollowerLib(lua_State *L); diff --git a/src/lua_script.c b/src/lua_script.c index 8a1e307bb..65d9b6da2 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -59,6 +59,7 @@ static lua_CFunction liblist[] = { LUA_PolyObjLib, // polyobj_t LUA_BlockmapLib, // blockmap stuff LUA_HudLib, // HUD stuff + LUA_FollowerLib, // follower_t, followers[] NULL };