Merge branch 'expose-more-lua-stuff' into 'next'

More Lua stuff + PlayerCmd hook

See merge request KartKrew/Kart-Public!28
This commit is contained in:
Sal 2019-01-26 13:19:41 -05:00
commit 910df92d5a
12 changed files with 229 additions and 16 deletions

View file

@ -1595,10 +1595,26 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
}
}
/* Lua: Allow this hook to overwrite ticcmd.
We check if we're actually in a level because for some reason this Hook would run in menus and on the titlescreen otherwise.
Be aware that within this hook, nothing but this player's cmd can be edited (otherwise we'd run in some pretty bad synching problems since this is clientsided, or something)
Possible usages for this are:
-Forcing the player to perform an action, which could otherwise require terrible, terrible hacking to replicate.
-Preventing the player to perform an action, which would ALSO require some weirdo hacks.
-Making some galaxy brain autopilot Lua if you're a masochist
-Making a Mario Kart 8 Deluxe tier baby mode that steers you away from walls and whatnot. You know what, do what you want!
*/
#ifdef HAVE_BLUA
if (gamestate == GS_LEVEL)
LUAh_PlayerCmd(player, cmd);
#endif
//Reset away view if a command is given.
if ((cmd->forwardmove || cmd->sidemove || cmd->buttons)
&& displayplayer != consoleplayer && ssplayer == 1)
displayplayer = consoleplayer;
}
// User has designated that they want

View file

@ -1548,7 +1548,7 @@ static void K_RegularVoiceTimers(player_t *player)
player->kartstuff[k_tauntvoices] = 4*TICRATE;
}
static void K_PlayAttackTaunt(mobj_t *source)
void K_PlayAttackTaunt(mobj_t *source)
{
sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons
boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]);
@ -1562,7 +1562,7 @@ static void K_PlayAttackTaunt(mobj_t *source)
K_TauntVoiceTimers(source->player);
}
static void K_PlayBoostTaunt(mobj_t *source)
void K_PlayBoostTaunt(mobj_t *source)
{
sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons
boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]);
@ -1576,7 +1576,7 @@ static void K_PlayBoostTaunt(mobj_t *source)
K_TauntVoiceTimers(source->player);
}
static void K_PlayOvertakeSound(mobj_t *source)
void K_PlayOvertakeSound(mobj_t *source)
{
boolean tasteful = (!source->player || !source->player->kartstuff[k_voices]);
@ -1596,7 +1596,7 @@ static void K_PlayOvertakeSound(mobj_t *source)
K_RegularVoiceTimers(source->player);
}
static void K_PlayHitEmSound(mobj_t *source)
void K_PlayHitEmSound(mobj_t *source)
{
if (cv_kartvoices.value)
S_StartSound(source, sfx_khitem);
@ -1606,7 +1606,7 @@ static void K_PlayHitEmSound(mobj_t *source)
K_RegularVoiceTimers(source->player);
}
static void K_PlayPowerGloatSound(mobj_t *source)
void K_PlayPowerGloatSound(mobj_t *source)
{
if (cv_kartvoices.value)
S_StartSound(source, sfx_kgloat);
@ -7038,15 +7038,23 @@ static boolean K_drawKartPositionFaces(void)
colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE);
V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, facerankprefix[players[rankplayer[i]].skin], colormap);
if (G_BattleGametype() && players[rankplayer[i]].kartstuff[k_bumper] > 0)
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_battlebumpers))
{
V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumper[0], colormap);
for (j = 1; j < players[rankplayer[i]].kartstuff[k_bumper]; j++)
#endif
if (G_BattleGametype() && players[rankplayer[i]].kartstuff[k_bumper] > 0)
{
bumperx += 5;
V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumper[1], colormap);
V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumper[0], colormap);
for (j = 1; j < players[rankplayer[i]].kartstuff[k_bumper]; j++)
{
bumperx += 5;
V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumper[1], colormap);
}
}
}
#ifdef HAVE_BLUA
} // A new level of stupidity: checking if lua is enabled to close a bracket. :Fascinating:
#endif
}
if (i == strank)
@ -7857,7 +7865,10 @@ static void K_drawBattleFullscreen(void)
return;
}
K_drawKartFreePlay(leveltime);
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_freeplay))
#endif
K_drawKartFreePlay(leveltime);
}
}
@ -8479,7 +8490,12 @@ void K_drawKartHUD(void)
// Draw FREE PLAY.
if (isfreeplay && !stplyr->spectator && timeinmap > 113)
K_drawKartFreePlay(leveltime);
{
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_freeplay))
#endif
K_drawKartFreePlay(leveltime);
}
if (cv_kartdebugdistribution.value)
K_drawDistributionDebugger();

View file

@ -65,6 +65,13 @@ void K_CalculateBattleWanted(void);
void K_CheckBumpers(void);
void K_CheckSpectateStatus(void);
// sound stuff for lua
void K_PlayAttackTaunt(mobj_t *source);
void K_PlayBoostTaunt(mobj_t *source);
void K_PlayOvertakeSound(mobj_t *source);
void K_PlayHitEmSound(mobj_t *source);
void K_PlayPowerGloatSound(mobj_t *source);
const char *K_GetItemPatch(UINT8 item, boolean tiny);
INT32 K_calcSplitFlags(INT32 snapflags);
void K_LoadKartHUDGraphics(void);

View file

@ -31,9 +31,10 @@
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // hook_cmd_running
#define NOHUD if (hud_running) return luaL_error(L, "HUD rendering code should not call this function!");
#define NOHUD if (hud_running) return luaL_error(L, "HUD rendering code should not call this function!"); else if (hook_cmd_running) return luaL_error(L, "CMD Building code should not call this function!");
// Yes technically cmd hook isn't a hud but whatever, this avoids having 2 defines for virtually the same thing.
boolean luaL_checkboolean(lua_State *L, int narg) {
luaL_checktype(L, narg, LUA_TBOOLEAN);
@ -2131,6 +2132,72 @@ static int lib_gTicsToMilliseconds(lua_State *L)
// K_KART
////////////
// Seriously, why weren't those exposed before?
static int lib_kAttackSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayAttackTaunt: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayAttackTaunt(mobj);
return 0;
}
static int lib_kBoostSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayBoostTaunt: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayBoostTaunt(mobj);
return 0;
}
static int lib_kOvertakeSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayOvertakeSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayOvertakeSound(mobj);
return 0;
}
static int lib_kHitEmSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayHitEmSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayHitEmSound(mobj);
return 0;
}
static int lib_kGloatSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayPowerGloatSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayPowerGloatSound(mobj);
return 0;
}
static int lib_kLossSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); // let's require a mobj for consistency with the other functions
sfxenum_t sfx_id;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayLossSound: mobj_t isn't a player object.");
sfx_id = ((skin_t *)mobj->skin)->soundsid[S_sfx[sfx_klose].skinsound];
S_StartSound(mobj, sfx_id);
return 0;
}
// Note: Pain, Death and Victory are already exposed.
static int lib_kGetKartColorByName(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
@ -2697,6 +2764,12 @@ static luaL_Reg lib[] = {
{"G_TicsToMilliseconds",lib_gTicsToMilliseconds},
// k_kart
{"K_PlayAttackTaunt", lib_kAttackSound},
{"K_PlayBoostTaunt", lib_kBoostSound},
{"K_PlayPowerGloatSund", lib_kGloatSound},
{"K_PlayOvertakeSound", lib_kOvertakeSound},
{"K_PlayLossSound", lib_kLossSound},
{"K_PlayHitEmSound", lib_kHitEmSound},
{"K_GetKartColorByName",lib_kGetKartColorByName},
{"K_IsPlayerLosing",lib_kIsPlayerLosing},
{"K_IsPlayerWanted",lib_kIsPlayerWanted},

View file

@ -50,11 +50,14 @@ enum hook {
hook_PlayerSpin, //SRB2KART
hook_PlayerExplode, //SRB2KART
hook_PlayerSquish, //SRB2KART
hook_PlayerCmd, //SRB2KART
hook_MAX // last hook
};
extern const char *const hookNames[];
extern boolean hook_cmd_running; // This is used by PlayerCmd and lua_playerlib to prevent anything from being wirtten to player while we run PlayerCmd.
void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load)
void LUAh_MapLoad(void); // Hook for map load
void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer
@ -93,4 +96,7 @@ UINT8 LUAh_ShouldSquish(player_t *player, mobj_t *inflictor, mobj_t *source); //
boolean LUAh_PlayerSpin(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_SpinPlayer. Allows Lua to execute code and/or overwrite its behavior.
boolean LUAh_PlayerExplode(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_ExplodePlayer. Allows Lua to execute code and/or overwrite its behavior.
boolean LUAh_PlayerSquish(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_SquishPlayer. Allows Lua to execute code and/or overwrite its behavior.
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them.
#endif

View file

@ -61,6 +61,7 @@ const char *const hookNames[hook_MAX+1] = {
"PlayerSpin",
"PlayerExplode",
"PlayerSquish",
"PlayerCmd",
NULL
};
@ -877,6 +878,47 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd)
return hooked;
}
// Hook for G_BuildTicCmd
boolean hook_cmd_running = false;
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd)
{
hook_p hookp;
boolean hooked = false;
if (!gL || !(hooksAvailable[hook_PlayerCmd/8] & (1<<(hook_PlayerCmd%8))))
return false;
lua_settop(gL, 0);
hook_cmd_running = true;
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_PlayerCmd)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, cmd, META_TICCMD);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
hook_cmd_running = false;
lua_settop(gL, 0);
return hooked;
}
// Hook for B_BuildTailsTiccmd by skin name
boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
{

View file

@ -20,8 +20,10 @@ enum hud {
hud_item,
hud_position,
hud_minirankings, // Rankings to the left
hud_battlebumpers, // mini rankings battle bumpers.
hud_wanted,
hud_speedometer,
hud_freeplay,
hud_rankings, // Tab rankings
hud_MAX

View file

@ -45,8 +45,10 @@ static const char *const hud_disable_options[] = {
"item",
"position",
"minirankings", // Gametype rankings to the left
"battlerankingsbumpers", // bumper drawer for battle. Useful if you want to make a custom battle gamemode without bumpers being involved.
"wanted",
"speedometer",
"freeplay",
"rankings",
NULL};
@ -482,6 +484,20 @@ static int libd_drawString(lua_State *L)
return 0;
}
static int libd_drawKartString(lua_State *L)
{
fixed_t x = luaL_checkinteger(L, 1);
fixed_t y = luaL_checkinteger(L, 2);
const char *str = luaL_checkstring(L, 3);
INT32 flags = luaL_optinteger(L, 4, V_ALLOWLOWERCASE);
flags &= ~V_PARAMMASK; // Don't let crashes happen.
HUDONLY
V_DrawKartString(x, y, flags, str);
return 0;
}
static int libd_stringWidth(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
@ -593,6 +609,7 @@ static luaL_Reg lib_draw[] = {
{"drawFill", libd_drawFill},
{"fadeScreen", libd_fadeScreen},
{"drawString", libd_drawString},
{"drawKartString", libd_drawKartString},
{"stringWidth", libd_stringWidth},
{"getColormap", libd_getColormap},
{"width", libd_width},

View file

@ -22,6 +22,7 @@
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // cmd errors
boolean LUA_CallAction(const char *action, mobj_t *actor);
state_t *astate;
@ -169,6 +170,8 @@ static int lib_setState(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter states in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter states in BuildCMD code!");
// clear the state to start with, in case of missing table elements
memset(state,0,sizeof(state_t));
@ -378,6 +381,8 @@ static int state_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter states in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter states in BuildCMD code!");
if (fastcmp(field,"sprite")) {
value = luaL_checknumber(L, 3);
@ -466,6 +471,8 @@ static int lib_setMobjInfo(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter mobjinfo in BuildCMD code!");
// clear the mobjinfo to start with, in case of missing table elements
memset(info,0,sizeof(mobjinfo_t));
@ -633,6 +640,8 @@ static int mobjinfo_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter mobjinfo in BuildCMD code!");
I_Assert(info != NULL);
I_Assert(info >= mobjinfo);
@ -755,6 +764,8 @@ static int lib_setSfxInfo(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter sfxinfo in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter sfxinfo in BuildCMD code!");
lua_pushnil(L);
while (lua_next(L, 1)) {
@ -830,6 +841,8 @@ static int sfxinfo_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter S_sfx in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter S_sfx in BuildCMD code!");
I_Assert(sfx != NULL);

View file

@ -24,6 +24,7 @@
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // cmd errors
#include "dehacked.h"
#include "fastcmp.h"
@ -484,6 +485,8 @@ static int sector_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter sector_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter sector_t in BuildCMD code!");
switch(field)
{
@ -1174,6 +1177,8 @@ static int ffloor_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter ffloor_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter ffloor_t in BuildCMD code!");
switch(field)
{
@ -1303,6 +1308,8 @@ static int slope_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter pslope_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter pslope_t in BuildCMD code!");
switch(field) // todo: reorganize this shit
{

View file

@ -21,6 +21,7 @@
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // cmd errors
static const char *const array_opt[] ={"iterate",NULL};
@ -391,6 +392,9 @@ static int mobj_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter mobj_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter mobj_t in BuildCMD code!");
switch(field)
{
case mobj_valid:
@ -756,6 +760,8 @@ static int mapthing_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter mapthing_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter mapthing_t in BuildCMD code!");
if(fastcmp(field,"x"))
mt->x = (INT16)luaL_checkinteger(L, 3);

View file

@ -21,6 +21,7 @@
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // hook_cmd_running
static int lib_iteratePlayers(lua_State *L)
{
@ -356,6 +357,9 @@ static int player_set(lua_State *L)
if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter player_t in BuildCMD code!");
if (fastcmp(field,"mo")) {
mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
plr->mo->player = NULL; // remove player pointer from old mobj
@ -667,6 +671,8 @@ static int power_set(lua_State *L)
return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p);
if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter player_t in BuildCMD code!");
powers[p] = i;
return 0;
}
@ -699,6 +705,8 @@ static int kartstuff_set(lua_State *L)
return luaL_error(L, LUA_QL("kartstufftype_t") " cannot be %u", ks);
if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter player_t in BuildCMD code!");
kartstuff[ks] = i;
return 0;
}