From 31a97adbf29eaa50b055184de59246828b835b88 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 13 Oct 2024 17:14:59 +0200 Subject: [PATCH 01/46] Implement itemlist_t in itemroulette_t for better Lua integration itemList -> itemList.items itemListLen -> itemList.len itemListCap -> itemList.cap --- src/d_player.h | 22 +++++++++++--------- src/k_botitem.cpp | 8 ++++---- src/k_hud.cpp | 14 ++++++------- src/k_roulette.c | 52 +++++++++++++++++++++++------------------------ src/p_saveg.cpp | 48 +++++++++++++++++++++---------------------- 5 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d440ecbfe..9a4f42f9e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -506,23 +506,25 @@ struct skybox_t { }; // player_t struct for item roulette variables - // Doing this the right way is causing problems. // so FINE, it's a static length now. #define ITEM_LIST_SIZE (NUMKARTRESULTS << 3) +typedef struct itemlist_t +{ + size_t len; +#ifdef ITEM_LIST_SIZE + SINT8 items[ITEM_LIST_SIZE]; +#else + SINT8 *items; + size_t cap; +#endif +} itemlist_t; + struct itemroulette_t { boolean active; - -#ifdef ITEM_LIST_SIZE - size_t itemListLen; - SINT8 itemList[ITEM_LIST_SIZE]; -#else - size_t itemListCap; - size_t itemListLen; - SINT8 *itemList; -#endif + itemlist_t itemList; UINT8 playing, exiting; UINT32 preexpdist, dist, baseDist; diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index d042f0faa..360c80c31 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -1863,7 +1863,7 @@ static void K_UpdateBotGameplayVarsItemUsageMash(player_t *player) else { botItemPriority_e currentPriority = K_GetBotItemPriority( - static_cast( player->itemRoulette.itemList[ player->itemRoulette.index ] ) + static_cast( player->itemRoulette.itemList.items[ player->itemRoulette.index ] ) ); if (player->botvars.roulettePriority == currentPriority) @@ -1877,7 +1877,7 @@ static void K_UpdateBotGameplayVarsItemUsageMash(player_t *player) // reduce priority until we get to a valid one. player->botvars.rouletteTimeout++; - if (player->botvars.rouletteTimeout > player->itemRoulette.itemListLen * player->itemRoulette.speed) + if (player->botvars.rouletteTimeout > player->itemRoulette.itemList.len * player->itemRoulette.speed) { player->botvars.roulettePriority--; player->botvars.rouletteTimeout = 0; @@ -1995,9 +1995,9 @@ void K_BotPickItemPriority(player_t *player) player->botvars.rouletteTimeout = 0; // Check for items that are extremely high priority. - for (i = 0; i < player->itemRoulette.itemListLen; i++) + for (i = 0; i < player->itemRoulette.itemList.len; i++) { - botItemPriority_e priority = K_GetBotItemPriority( static_cast( player->itemRoulette.itemList[i] ) ); + botItemPriority_e priority = K_GetBotItemPriority( static_cast( player->itemRoulette.itemList.items[i] ) ); if (priority < BOT_ITEM_PR__OVERRIDES) { diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 5bfc23d9f..c70078181 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -1619,15 +1619,15 @@ static void K_drawKartItem(void) boolean flashOnOne = false; boolean flashOnTwo = false; - if (stplyr->itemRoulette.itemListLen > 0) + if (stplyr->itemRoulette.itemList.len > 0) { // Init with item roulette stuff. for (i = 0; i < 3; i++) { const SINT8 indexOfs = i-1; - const size_t index = (stplyr->itemRoulette.itemListLen + (stplyr->itemRoulette.index + indexOfs)) % stplyr->itemRoulette.itemListLen; + const size_t index = (stplyr->itemRoulette.itemList.len + (stplyr->itemRoulette.index + indexOfs)) % stplyr->itemRoulette.itemList.len; - const SINT8 result = stplyr->itemRoulette.itemList[index]; + const SINT8 result = stplyr->itemRoulette.itemList.items[index]; const SINT8 item = K_ItemResultToType(result); const boolean usingDebugItemAmount = cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == item && cv_kartdebugamount.value > 1; const UINT8 amt = usingDebugItemAmount ? cv_kartdebugamount.value : K_ItemResultToAmount(result, &stplyr->itemRoulette); @@ -2133,15 +2133,15 @@ static void K_drawKartSlotMachine(void) vector2_t rouletteCrop = {10, 10}; INT32 i; - if (stplyr->itemRoulette.itemListLen > 0) + if (stplyr->itemRoulette.itemList.len > 0) { // Init with item roulette stuff. for (i = 0; i < 3; i++) { const SINT8 indexOfs = i-1; - const size_t index = (stplyr->itemRoulette.itemListLen + (stplyr->itemRoulette.index + indexOfs)) % stplyr->itemRoulette.itemListLen; + const size_t index = (stplyr->itemRoulette.itemList.len + (stplyr->itemRoulette.index + indexOfs)) % stplyr->itemRoulette.itemList.len; - const SINT8 result = stplyr->itemRoulette.itemList[index]; + const SINT8 result = stplyr->itemRoulette.itemList.items[index]; localpatch[i] = K_GetCachedSlotMachinePatch(result, offset); } @@ -7053,7 +7053,7 @@ static void K_drawDistributionDebugger(void) V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+58, V_SNAPTOTOP|V_SNAPTORIGHT, va("secondToFirst = %u", rouletteData.secondToFirst)); #ifndef ITEM_LIST_SIZE - Z_Free(rouletteData.itemList); + Z_Free(rouletteData.itemList.items); #endif } diff --git a/src/k_roulette.c b/src/k_roulette.c index 0ec6a8a71..7b88c9cac 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -773,23 +773,23 @@ static void K_InitRoulette(itemroulette_t *const roulette) size_t i; #ifndef ITEM_LIST_SIZE - if (roulette->itemList == NULL) + if (roulette->itemList.items == NULL) { - roulette->itemListCap = 8; - roulette->itemList = Z_Calloc( - sizeof(SINT8) * roulette->itemListCap, + roulette->itemList.cap = 8; + roulette->itemList.items = Z_Calloc( + sizeof(SINT8) * roulette->itemList.cap, PU_STATIC, - &roulette->itemList + &roulette->itemList.items ); - if (roulette->itemList == NULL) + if (roulette->itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); } } #endif - roulette->itemListLen = 0; + roulette->itemList.len = 0; roulette->index = 0; roulette->baseDist = roulette->dist = 0; @@ -876,33 +876,33 @@ static void K_InitRoulette(itemroulette_t *const roulette) static void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) { #ifdef ITEM_LIST_SIZE - if (roulette->itemListLen >= ITEM_LIST_SIZE) + if (roulette->itemList.len >= ITEM_LIST_SIZE) { I_Error("Out of space for item reel! Go and make ITEM_LIST_SIZE bigger I guess?\n"); return; } #else - I_Assert(roulette->itemList != NULL); + I_Assert(roulette->itemList.items != NULL); - if (roulette->itemListLen >= roulette->itemListCap) + if (roulette->itemList.len >= roulette->itemList.cap) { - roulette->itemListCap *= 2; - roulette->itemList = Z_Realloc( - roulette->itemList, - sizeof(SINT8) * roulette->itemListCap, + roulette->itemList.cap *= 2; + roulette->itemList.items = Z_Realloc( + roulette->itemList.items, + sizeof(SINT8) * roulette->itemList.cap, PU_STATIC, - &roulette->itemList + &roulette->itemList.items ); - if (roulette->itemList == NULL) + if (roulette->itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); } } #endif - roulette->itemList[ roulette->itemListLen ] = item; - roulette->itemListLen++; + roulette->itemList.items[ roulette->itemList.len ] = item; + roulette->itemList.len++; } /*-------------------------------------------------- @@ -1767,7 +1767,7 @@ void K_StartItemRoulette(player_t *const player, boolean ringbox) K_FillItemRouletteData(player, roulette, ringbox, false); if (roulette->autoroulette) - roulette->index = P_RandomRange(PR_AUTOROULETTE, 0, roulette->itemListLen - 1); + roulette->index = P_RandomRange(PR_AUTOROULETTE, 0, roulette->itemList.len - 1); if (K_PlayerUsesBotMovement(player) == true) { @@ -1776,9 +1776,9 @@ void K_StartItemRoulette(player_t *const player, boolean ringbox) // Prevent further duplicates of items that // are intended to only have one out at a time. - for (i = 0; i < roulette->itemListLen; i++) + for (i = 0; i < roulette->itemList.len; i++) { - kartitems_t item = roulette->itemList[i]; + kartitems_t item = roulette->itemList.items[i]; if (K_ItemSingularity(item) == true) { K_SetItemCooldown(item, TICRATE<<4); @@ -1907,9 +1907,9 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd) return; } - if (roulette->itemListLen == 0 + if (roulette->itemList.len == 0 #ifndef ITEM_LIST_SIZE - || roulette->itemList == NULL + || roulette->itemList.items == NULL #endif ) { @@ -1972,7 +1972,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd) if (fudgedDelay > gap) // Did the roulette tick over in-flight? { fudgedDelay = fudgedDelay - gap; // We're compensating for this gap's worth of delay, so cut it down. - roulette->index = roulette->index == 0 ? roulette->itemListLen - 1 : roulette->index - 1; // Roll the roulette index back... + roulette->index = roulette->index == 0 ? roulette->itemList.len - 1 : roulette->index - 1; // Roll the roulette index back... roulette->tics = 0; // And just in case our delay is SO high that a fast roulette needs to roll back again... } else @@ -1984,7 +1984,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd) // And one more nudge for the remaining delay. roulette->tics = (roulette->tics + fudgedDelay) % roulette->speed; - INT32 finalItem = roulette->itemList[ roulette->index ]; + INT32 finalItem = roulette->itemList.items[ roulette->index ]; if (roulette->ringbox == true) { @@ -2029,7 +2029,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd) if (roulette->tics == 0) { - roulette->index = (roulette->index + 1) % roulette->itemListLen; + roulette->index = (roulette->index + 1) % roulette->itemList.len; roulette->tics = roulette->speed; // This makes the roulette produce the random noises. diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 2351cc64b..fe8f3045d 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -774,33 +774,33 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].itemRoulette.active); #ifdef ITEM_LIST_SIZE - WRITEUINT32(save->p, players[i].itemRoulette.itemListLen); + WRITEUINT32(save->p, players[i].itemRoulette.itemList.len); for (q = 0; q < ITEM_LIST_SIZE; q++) { - if (q >= players[i].itemRoulette.itemListLen) + if (q >= players[i].itemRoulette.itemList.len) { WRITESINT8(save->p, KITEM_NONE); } else { - WRITESINT8(save->p, players[i].itemRoulette.itemList[q]); + WRITESINT8(save->p, players[i].itemRoulette.itemList.items[q]); } } #else - if (players[i].itemRoulette.itemList == NULL) + if (players[i].itemRoulette.itemList.items == NULL) { WRITEUINT32(save->p, 0); WRITEUINT32(save->p, 0); } else { - WRITEUINT32(save->p, players[i].itemRoulette.itemListCap); - WRITEUINT32(save->p, players[i].itemRoulette.itemListLen); + WRITEUINT32(save->p, players[i].itemRoulette.itemList.cap); + WRITEUINT32(save->p, players[i].itemRoulette.itemList.len); - for (q = 0; q < players[i].itemRoulette.itemListLen; q++) + for (q = 0; q < players[i].itemRoulette.itemList.len; q++) { - WRITESINT8(save->p, players[i].itemRoulette.itemList[q]); + WRITESINT8(save->p, players[i].itemRoulette.itemList.items[q]); } } #endif @@ -1435,44 +1435,44 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].itemRoulette.active = (boolean)READUINT8(save->p); #ifdef ITEM_LIST_SIZE - players[i].itemRoulette.itemListLen = (size_t)READUINT32(save->p); + players[i].itemRoulette.itemList.len = (size_t)READUINT32(save->p); for (q = 0; q < ITEM_LIST_SIZE; q++) { - players[i].itemRoulette.itemList[q] = READSINT8(save->p); + players[i].itemRoulette.itemList.items[q] = READSINT8(save->p); } #else - players[i].itemRoulette.itemListCap = (size_t)READUINT32(save->p); - players[i].itemRoulette.itemListLen = (size_t)READUINT32(save->p); + players[i].itemRoulette.itemList.cap = (size_t)READUINT32(save->p); + players[i].itemRoulette.itemList.len = (size_t)READUINT32(save->p); - if (players[i].itemRoulette.itemListCap > 0) + if (players[i].itemRoulette.itemList.cap > 0) { - if (players[i].itemRoulette.itemList == NULL) + if (players[i].itemRoulette.itemList.items == NULL) { - players[i].itemRoulette.itemList = Z_Calloc( - sizeof(SINT8) * players[i].itemRoulette.itemListCap, + players[i].itemRoulette.itemList.items = Z_Calloc( + sizeof(SINT8) * players[i].itemRoulette.itemList.cap, PU_STATIC, - &players[i].itemRoulette.itemList + &players[i].itemRoulette.itemList.items ); } else { - players[i].itemRoulette.itemList = Z_Realloc( - players[i].itemRoulette.itemList, - sizeof(SINT8) * players[i].itemRoulette.itemListCap, + players[i].itemRoulette.itemList.items = Z_Realloc( + players[i].itemRoulette.itemList.items, + sizeof(SINT8) * players[i].itemRoulette.itemList.cap, PU_STATIC, - &players[i].itemRoulette.itemList + &players[i].itemRoulette.itemList.items ); } - if (players[i].itemRoulette.itemList == NULL) + if (players[i].itemRoulette.itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); } - for (q = 0; q < players[i].itemRoulette.itemListLen; q++) + for (q = 0; q < players[i].itemRoulette.itemList.len; q++) { - players[i].itemRoulette.itemList[q] = READSINT8(save->p); + players[i].itemRoulette.itemList.items[q] = READSINT8(save->p); } } #endif From 12ab7185e1725c88ff9b625b5f512e8d7807edaf Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 13 Oct 2024 13:34:06 +0200 Subject: [PATCH 02/46] Item Roulette lib (includes getters and setters so far) --- src/CMakeLists.txt | 1 + src/lua_baselib.c | 2 + src/lua_itemroulettelib.c | 281 ++++++++++++++++++++++++++++++++++++++ src/lua_libs.h | 3 + src/lua_playerlib.c | 8 +- src/lua_script.c | 1 + 6 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 src/lua_itemroulettelib.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ec00e3114..1d1ddcdee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 lua_hudlib.c lua_hudlib_drawlist.c lua_followerlib.c + lua_itemroulettelib.c lua_profile.cpp k_kart.c k_respawn.c diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 873056643..b21457c30 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -232,6 +232,8 @@ static const struct { {META_ACTIVATOR, "activator_t"}, {META_FOLLOWER, "follower_t"}, + {META_ITEMROULETTE, "itemroulette_t"}, + {META_ITEMROULETTE_ITEMLIST, "itemroulette_t.itemlist_t"}, {NULL, NULL} }; diff --git a/src/lua_itemroulettelib.c b/src/lua_itemroulettelib.c new file mode 100644 index 000000000..fa7b5e251 --- /dev/null +++ b/src/lua_itemroulettelib.c @@ -0,0 +1,281 @@ +// 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_itemroulettelib.c +/// \brief player item roulette structure library for Lua scripting + +#include "doomdef.h" +#include "fastcmp.h" +#include "d_player.h" +#include "z_zone.h" +#include "k_roulette.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 itemroulette { + itemroulette_valid = 0, + itemroulette_active, + itemroulette_itemlist, + itemroulette_useodds, + itemroulette_playing, + itemroulette_exiting, + itemroulette_dist, + itemroulette_basedist, + itemroulette_firstdist, + itemroulette_seconddist, + itemroulette_secondtofirst, + itemroulette_index, + itemroulette_sound, + itemroulette_speed, + itemroulette_tics, + itemroulette_elapsed, + itemroulette_eggman, + itemroulette_ringbox, + itemroulette_autoroulette, + itemroulette_reserved +}; +static const char *const itemroulette_opt[] = { + "valid", + "active", + "itemlist", + "useodds", + "playing", + "exiting", + "dist", + "basedist", + "firstdist", + "seconddist", + "secondtofirst", + "index", + "sound", + "speed", + "tics", + "elapsed", + "eggman", + "ringbox", + "autoroulette", + "reserved", + NULL +}; + +static int itemroulette_get(lua_State *L) +{ + itemroulette_t *itemroulette = *((itemroulette_t **)luaL_checkudata(L, 1, META_ITEMROULETTE)); + enum itemroulette field = luaL_checkoption(L, 2, itemroulette_opt[0], itemroulette_opt); + + // if this is null, welcome to parking garage rally circuit + I_Assert(itemroulette != NULL); + + switch (field) + { + case itemroulette_valid: + lua_pushboolean(L, itemroulette != NULL); + break; + case itemroulette_active: + lua_pushboolean(L, itemroulette->active); + break; + case itemroulette_itemlist: + LUA_PushUserdata(L, &itemroulette->itemList, META_ITEMROULETTE_ITEMLIST); + break; + case itemroulette_useodds: + lua_pushinteger(L, itemroulette->useOdds); + break; + case itemroulette_playing: + lua_pushinteger(L, itemroulette->playing); + break; + case itemroulette_exiting: + lua_pushinteger(L, itemroulette->exiting); + break; + case itemroulette_dist: + lua_pushinteger(L, itemroulette->dist); + break; + case itemroulette_basedist: + lua_pushinteger(L, itemroulette->baseDist); + break; + case itemroulette_firstdist: + lua_pushinteger(L, itemroulette->firstDist); + break; + case itemroulette_seconddist: + lua_pushinteger(L, itemroulette->secondDist); + break; + case itemroulette_secondtofirst: + lua_pushinteger(L, itemroulette->secondToFirst); + break; + case itemroulette_index: + lua_pushinteger(L, itemroulette->index); + break; + case itemroulette_sound: + lua_pushinteger(L, itemroulette->sound); + break; + case itemroulette_speed: + lua_pushinteger(L, itemroulette->speed); + break; + case itemroulette_tics: + lua_pushinteger(L, itemroulette->tics); + break; + case itemroulette_elapsed: + lua_pushinteger(L, itemroulette->elapsed); + break; + case itemroulette_eggman: + lua_pushboolean(L, itemroulette->eggman); + break; + case itemroulette_ringbox: + lua_pushboolean(L, itemroulette->ringbox); + break; + case itemroulette_autoroulette: + lua_pushboolean(L, itemroulette->autoroulette); + break; + case itemroulette_reserved: + lua_pushinteger(L, itemroulette->reserved); + break; + } + + return 1; +} + +#define NOSET luaL_error(L, LUA_QL("itemroulette_t") " field " LUA_QS " should not be set directly.", itemroulette_opt[field]) +#define UNIMPLEMENTED luaL_error(L, LUA_QL("itemroulette_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", itemroulette_opt[field]) +#define NOSETITEMLIST luaL_error(L, LUA_QL("itemroulette_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("K_AddItemToReel") ", " LUA_QL("K_PushToRouletteItemList") ", or " LUA_QL("K_StartItemRoulette") ", or " LUA_QL("K_StopRoulette") " instead.", itemroulette_opt[field]) + +static int itemroulette_set(lua_State *L) +{ + itemroulette_t *itemroulette = *((itemroulette_t **)luaL_checkudata(L, 1, META_ITEMROULETTE)); + enum itemroulette field = luaL_checkoption(L, 2, itemroulette_opt[0], itemroulette_opt); + + // if this is null, welcome to parking garage rally circuit + I_Assert(itemroulette != NULL); + + INLEVEL + + if (hud_running) + return luaL_error(L, "Do not alter itemroulette_t in HUD rendering code!"); + if (hook_cmd_running) + return luaL_error(L, "Do not alter itemroulette_t in CMD building code!"); + + switch(field) + { + case itemroulette_valid: + return NOSET; + case itemroulette_active: + itemroulette->active = luaL_checkboolean(L, 3); + break; + case itemroulette_itemlist: + return NOSETITEMLIST; + case itemroulette_useodds: + itemroulette->useOdds = luaL_checkinteger(L, 3); + break; + case itemroulette_playing: + itemroulette->playing = luaL_checkinteger(L, 3); + break; + case itemroulette_exiting: + itemroulette->exiting = luaL_checkinteger(L, 3); + break; + case itemroulette_dist: + itemroulette->dist = luaL_checkinteger(L, 3); + break; + case itemroulette_basedist: + itemroulette->baseDist = luaL_checkinteger(L, 3); + break; + case itemroulette_firstdist: + itemroulette->firstDist = luaL_checkinteger(L, 3); + break; + case itemroulette_seconddist: + itemroulette->secondDist = luaL_checkinteger(L, 3); + break; + case itemroulette_secondtofirst: + itemroulette->secondToFirst = luaL_checkinteger(L, 3); + break; + case itemroulette_index: + itemroulette->index = luaL_checkinteger(L, 3); + break; + case itemroulette_sound: + itemroulette->sound = luaL_checkinteger(L, 3); + break; + case itemroulette_speed: + itemroulette->speed = luaL_checkinteger(L, 3); + break; + case itemroulette_tics: + itemroulette->tics = luaL_checkinteger(L, 3); + break; + case itemroulette_elapsed: + itemroulette->elapsed = luaL_checkinteger(L, 3); + break; + case itemroulette_eggman: + itemroulette->eggman = luaL_checkboolean(L, 3); + break; + case itemroulette_ringbox: + itemroulette->ringbox = luaL_checkboolean(L, 3); + break; + case itemroulette_autoroulette: + itemroulette->autoroulette = luaL_checkboolean(L, 3); + break; + case itemroulette_reserved: + itemroulette->reserved = luaL_checkinteger(L, 3); + break; + } + return 0; +} + +#undef NOSET +#undef NOSETITEMLIST +#undef UNIMPLEMENTED + +// itemlist, i -> itemlist[i] +static int itemrouletteitemlist_get(lua_State *L) +{ + itemlist_t *itemlist = *((itemlist_t **)luaL_checkudata(L, 1, META_ITEMROULETTE_ITEMLIST)); + size_t index = luaL_checkint(L, 2); + + if (index == 0 || index > itemlist->len) { + return luaL_error(L, LUA_QL("itemroulette_t.itemlist_t") " index cannot be %d", index); + } + lua_pushinteger(L, itemlist->items[index-1]); + return 1; +} + +static int itemrouletteitemlist_set(lua_State *L) +{ + return luaL_error(L, LUA_QL("itemroulette_t.itemlist_t") " struct cannot be edited by Lua."); +} + +// #itemlist -> itemList.len +static int itemrouletteitemlist_len(lua_State* L) +{ + itemlist_t *itemlist = *((itemlist_t **)luaL_checkudata(L, 1, META_ITEMROULETTE_ITEMLIST)); + lua_pushinteger(L, itemlist->len); + return 1; +} + +int LUA_ItemRouletteLib(lua_State *L) +{ + luaL_newmetatable(L, META_ITEMROULETTE); + lua_pushcfunction(L, itemroulette_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, itemroulette_set); + lua_setfield(L, -2, "__newindex"); + lua_pop(L,1); + + luaL_newmetatable(L, META_ITEMROULETTE_ITEMLIST); + lua_pushcfunction(L, itemrouletteitemlist_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, itemrouletteitemlist_set); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, itemrouletteitemlist_len); + lua_setfield(L, -2, "__len"); + lua_pop(L,1); + + return 0; +} \ No newline at end of file diff --git a/src/lua_libs.h b/src/lua_libs.h index 73d7b4f6e..7dc3f3380 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -103,6 +103,8 @@ extern lua_State *gL; #define META_ACTIVATOR "ACTIVATOR_T*" #define META_FOLLOWER "FOLLOWER_T*" +#define META_ITEMROULETTE "ITEMROULETTE_T" +#define META_ITEMROULETTE_ITEMLIST "ITEMROULETTE_T.ITEMLIST" boolean luaL_checkboolean(lua_State *L, int narg); @@ -123,6 +125,7 @@ int LUA_PolyObjLib(lua_State *L); int LUA_BlockmapLib(lua_State *L); int LUA_HudLib(lua_State *L); int LUA_FollowerLib(lua_State *L); +int LUA_ItemRouletteLib(lua_State *L); #ifdef __cplusplus } // extern "C" diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 65e2b894a..9ca6c5853 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -438,10 +438,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->tripwireUnstuck); else if (fastcmp(field,"bumpunstuck")) lua_pushinteger(L, plr->bumpUnstuck); - /* else if (fastcmp(field,"itemroulette")) - lua_pushinteger(L, plr->itemroulette); - */ + LUA_PushUserdata(L, &plr->itemRoulette, META_ITEMROULETTE); else if (fastcmp(field,"itemtype")) lua_pushinteger(L, plr->itemtype); else if (fastcmp(field,"itemamount")) @@ -1081,10 +1079,8 @@ static int player_set(lua_State *L) plr->tripwireUnstuck = luaL_checkinteger(L, 3); else if (fastcmp(field,"bumpunstuck")) plr->bumpUnstuck = luaL_checkinteger(L, 3); - /* else if (fastcmp(field,"itemroulette")) - plr->itemroulette = luaL_checkinteger(L, 3); - */ + return NOSET; else if (fastcmp(field,"itemtype")) plr->itemtype = luaL_checkinteger(L, 3); else if (fastcmp(field,"itemamount")) diff --git a/src/lua_script.c b/src/lua_script.c index 1f01010cb..cda71ff13 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -61,6 +61,7 @@ static lua_CFunction liblist[] = { LUA_BlockmapLib, // blockmap stuff LUA_HudLib, // HUD stuff LUA_FollowerLib, // follower_t, followers[] + LUA_ItemRouletteLib, // itemroulette_t NULL }; From 52b7ec0a428a164cb938752e1277f4b341203b96 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 4 Jul 2025 15:16:41 -0400 Subject: [PATCH 03/46] Roulette fixup --- src/k_hud.cpp | 2 +- src/k_roulette.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index c70078181..98d497850 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -1814,7 +1814,7 @@ static void K_drawKartItem(void) } UINT8 *boxmap = NULL; - if (stplyr->itemRoulette.active && (stplyr->itemRoulette.speed - stplyr->itemRoulette.tics < 3) && stplyr->itemRoulette.index == 0 && stplyr->itemRoulette.itemListLen > 1) + if (stplyr->itemRoulette.active && (stplyr->itemRoulette.speed - stplyr->itemRoulette.tics < 3) && stplyr->itemRoulette.index == 0 && stplyr->itemRoulette.itemList.len > 1) { boxmap = R_GetTranslationColormap(TC_ALLWHITE, SKINCOLOR_WHITE, GTC_CACHE); } diff --git a/src/k_roulette.c b/src/k_roulette.c index 7b88c9cac..1421ae1cf 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -2042,7 +2042,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd) else S_StartSound(NULL, sfx_itrol1 + roulette->sound); - if (roulette->index == 0 && roulette->itemListLen > 1) + if (roulette->index == 0 && roulette->itemList.len > 1) { S_StartSound(NULL, sfx_kc50); S_StartSound(NULL, sfx_kc50); From e5a20fdc3d3682644ec2b7a26daedcdfae0cb02b Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 19 Oct 2024 19:58:01 +0200 Subject: [PATCH 04/46] Expose ringbox results to Lua --- src/deh_tables.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index a880a1766..8caad3c35 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5225,6 +5225,15 @@ struct int_const_s const INT_CONST[] = { {"ENDOFPOWERUPS",ENDOFPOWERUPS}, {"LASTPOWERUP",LASTPOWERUP}, {"NUMPOWERUPS",NUMPOWERUPS}, + + // kartslotmachine_t + {"KSM_BAR", KSM_BAR}, + {"KSM_DOUBLEBAR", KSM_DOUBLEBAR}, + {"KSM_TRIPLEBAR", KSM_TRIPLEBAR}, + {"KSM_RING", KSM_RING}, + {"KSM_SEVEN", KSM_SEVEN}, + {"KSM_JACKPOT", KSM_JACKPOT}, + {"KSM__MAX", KSM__MAX}, // kartshields_t {"KSHIELD_NONE",KSHIELD_NONE}, From 2f7abb7dd30214a4ce7f3f21eaa80bb52523dfe3 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 19 Oct 2024 20:19:29 +0200 Subject: [PATCH 05/46] Expose PreFillItemRoulette hook for Lua --- src/k_roulette.c | 14 ++++++++++++++ src/lua_hook.h | 2 ++ src/lua_hooklib.c | 30 ++++++++++++++++++++++++++++++ src/lua_playerlib.c | 4 ++++ src/lua_playerlib.h | 27 +++++++++++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 src/lua_playerlib.h diff --git a/src/k_roulette.c b/src/k_roulette.c index 1421ae1cf..10c475610 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1256,6 +1256,20 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet K_CalculateRouletteSpeed(roulette); } + + // The roulette should be init'd first, and the speed should be + // set if applicable before you can override anything. + { + if (LUA_HookPreFillItemRoulette(player, roulette, ringbox)) + { + // If somehow there's no items, add sad. + if (roulette->itemList.len == 0) { + K_AddItemToReel(player, roulette, KITEM_SAD); + } + return; + } + + } if (ringbox == true) { diff --git a/src/lua_hook.h b/src/lua_hook.h index 12c85be94..1f392d868 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -79,6 +79,7 @@ automatically. X (GameQuit),\ X (PlayerCmd),/* building the player's ticcmd struct */\ X (VoteThinker),/* Y_VoteTicker */\ + X (PreFillItemRoulette),/* K_FillItemRouletteData, before special conditions but after roulette speed calc */\ #define STRING_HOOK_LIST(X) \ X (SpecialExecute),\ @@ -146,6 +147,7 @@ void LUA_HookPlayerQuit(player_t *, kickreason_t); //int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend); +int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); #ifdef __cplusplus } // extern "C" diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 676e40b77..0d1771f74 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -24,6 +24,7 @@ #include "lua_hook.h" #include "lua_hud.h" // hud_running errors #include "lua_profile.h" +#include "lua_playerlib.h" // constplayer #include "command.h" #include "m_perfstats.h" @@ -1009,4 +1010,33 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend) return hook.status; } +static int roulette_hook( + player_t *player, + itemroulette_t *const roulette, + boolean ringbox, + int hook_type, + Hook_Callback results_handler) +{ + Hook_State hook; + if (prepare_hook(&hook, false, hook_type)) + { + if (player == NULL) { + lua_pushnil(gL); + } else { + LUA_PushUserdata(gL, player, META_PLAYER); + } + LUA_PushUserdata(gL, roulette, META_ITEMROULETTE); + lua_pushboolean(gL, ringbox); + constplayer = true; // Do not allow players to be modified. + call_hooks(&hook, 1, results_handler); + constplayer = false; // You're good. + } + return hook.status; +} + +int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox) +{ + return roulette_hook(player, roulette, ringbox, HOOK(PreFillItemRoulette), res_true); +} + boolean hook_cmd_running = false; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 9ca6c5853..8ba0b1393 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -25,6 +25,8 @@ #include "lua_hook.h" // hook_cmd_running errors #include "k_profiles.h" // GetPrettyRRID +boolean constplayer = false; + static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; @@ -795,6 +797,8 @@ static int player_set(lua_State *L) 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 CMD building code!"); + if (constplayer) + return luaL_error(L, "Do not alter player_t while modifying the roulette!"); if (fastcmp(field,"mo")) { mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); diff --git a/src/lua_playerlib.h b/src/lua_playerlib.h new file mode 100644 index 000000000..d2d09f5a5 --- /dev/null +++ b/src/lua_playerlib.h @@ -0,0 +1,27 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Kart Krew. +// Copyright (C) 2022 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_playerlib.h +/// \brief LUA Player library header. + +#ifndef __LUA_PLAYER_H__ +#define __LUA_PLAYER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern boolean constplayer; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __LUA_PLAYER_H__ From f1898078c293dd8e1ced33c9ca3ec6a889cdf01e Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 19 Oct 2024 20:28:48 +0200 Subject: [PATCH 06/46] Expose K_ItemEnabled, K_ItemSingularity and K_GetBotItemPriority to Lua --- src/lua_baselib.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b21457c30..654542cae 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -46,6 +46,7 @@ #include "lua_hud.h" // hud_running errors #include "taglist.h" // P_FindSpecialLineFromTag #include "lua_hook.h" // hook_cmd_running errors +#include "k_roulette.h" #define NOHUD if (hud_running)\ return luaL_error(L, "HUD rendering code should not call this function!");\ @@ -4059,6 +4060,27 @@ static int lib_vsRandomPointOnArena(lua_State *L) return 2; } +static int lib_kItemEnabled(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + lua_pushboolean(L, K_ItemEnabled(item)); + return 1; +} + +static int lib_kItemSingularity(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + lua_pushboolean(L, K_ItemSingularity(item)); + return 1; +} + +static int lib_kGetBotItemPriority(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + lua_pushinteger(L, K_GetBotItemPriority(item)); + return 1; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4344,6 +4366,11 @@ static luaL_Reg lib[] = { {"VS_GetArena", lib_vsGetArena}, {"VS_PredictAroundArena", lib_vsPredictAroundArena}, {"VS_RandomPointOnArena", lib_vsRandomPointOnArena}, + + // k_roulette + {"K_ItemEnabled", lib_kItemEnabled}, + {"K_ItemSingularity", lib_kItemSingularity}, + {"K_GetBotItemPriority", lib_kGetBotItemPriority}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From a6f228ec2988423a26853a0524bee91073994880 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 19 Oct 2024 20:39:26 +0200 Subject: [PATCH 07/46] Expose K_AddItemToReel and K_PushToRouletteItemList to Lua --- src/k_roulette.c | 35 +++---------- src/k_roulette.h | 36 ++++++++++++++ src/lua_baselib.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 28 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 10c475610..9604347e0 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -860,20 +860,11 @@ static void K_InitRoulette(itemroulette_t *const roulette) } /*-------------------------------------------------- - static void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) + void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) - Pushes a new item to the end of the item - roulette's item list. Also accepts slot machine - values instead of items. - - Input Arguments:- - roulette - The item roulette data to modify. - item - The item / slot machine index to push to the list. - - Return:- - N/A + See header file for description. --------------------------------------------------*/ -static void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) +void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) { #ifdef ITEM_LIST_SIZE if (roulette->itemList.len >= ITEM_LIST_SIZE) @@ -906,23 +897,11 @@ static void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) } /*-------------------------------------------------- - static void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item) + void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item) - Adds an item to a player's item reel. Unlike - pushing directly with K_PushToRouletteItemList, - this function handles special behaviors (like - padding with extra Super Rings). - - Input Arguments:- - player - The player to add to the item roulette. - This is valid to be NULL. - roulette - The player's item roulette data. - item - The item to push to the list. - - Return:- - N/A + See header file for description. --------------------------------------------------*/ -static void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item) +void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item) { K_PushToRouletteItemList(roulette, item); @@ -1270,7 +1249,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet } } - + if (ringbox == true) { // If this is being invoked by a Ring Box, it should literally never produce items. diff --git a/src/k_roulette.h b/src/k_roulette.h index 6f3054c5e..fba9ef9f6 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -76,6 +76,42 @@ boolean K_ItemSingularity(kartitems_t item); botItemPriority_e K_GetBotItemPriority(kartitems_t result); +/*-------------------------------------------------- + void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) + + Pushes a new item to the end of the item + roulette's item list. Also accepts slot machine + values instead of items. + + Input Arguments:- + roulette - The item roulette data to modify. + item - The item / slot machine index to push to the list. + + Return:- + N/A +--------------------------------------------------*/ + +void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item); + +/*-------------------------------------------------- + void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item) + + Adds an item to a player's item reel. Unlike + pushing directly with K_PushToRouletteItemList, + this function handles special behaviors (like + padding with extra Super Rings). + + Input Arguments:- + player - The player to add to the item roulette. + This is valid to be NULL. + roulette - The player's item roulette data. + item - The item to push to the list. + + Return:- + N/A +--------------------------------------------------*/ + +void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item); /*-------------------------------------------------- INT32 K_KartGetBattleOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 654542cae..b7fbbdc86 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4081,6 +4081,128 @@ static int lib_kGetBotItemPriority(lua_State *L) return 1; } +static void getItemRouletteOrPlayerBasedOnFirstParam(lua_State *L, player_t **player, itemroulette_t **itemRoulette) +{ + /* + JugadorXEI @ 11/01/2024 (MM/DD/AAAA): + Ok, so. + I implemented luaL_testudata from Lua 5.2 because I wanted to test if an argument + was one userdata type or the other, and it worked. ...And then it didn't work, for some reason. + I was debugging this for 4 hours and couldn't figure it out. + So, raw-ass Lua funcs, here we go. THIS works. + Working with pointers gives me a headache. + */ + void *p = lua_touserdata(L, 1); + if (p != NULL) + { + if (lua_getmetatable(L, 1)) + { + lua_getfield(L, LUA_REGISTRYINDEX, META_ITEMROULETTE); + if (lua_rawequal(L, -1, -2)) + { + *itemRoulette = *(itemroulette_t **)p; + } + else + { + lua_pop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, META_PLAYER); + if (lua_rawequal(L, -1, -2)) + { + *player = *(player_t **)p; + *itemRoulette = &(*player)->itemRoulette; + } + lua_pop(L, 2); + } + } + } +} + +static int lib_kAddItemToReel(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + if (lua_isnumber(L, 2)) + { + kartitems_t item = luaL_checkinteger(L, 2); + K_AddItemToReel(player, itemRoulette, item); + } + else if (lua_istable(L, 2)) + { + luaL_checktype(L, 2, LUA_TTABLE); + size_t size = luaL_getn(L, 2); + + for (size_t i = 1; i <= size; i++) + { + lua_rawgeti(L, 2, i); + if (lua_isnumber(L, -1)) + { + kartitems_t item = luaL_checkinteger(L, -1); + K_AddItemToReel(player, itemRoulette, item); + } + else // Quit early, let the scripter know they messed up. + { + lua_pop(L, 1); + return luaL_error(L, "Non-integer value in table in index %d.", i); + } + lua_pop(L, 1); + } + } + else return LUA_ErrInvalid(L, "integer/table"); + + return 0; +} + +static int lib_kPushToRouletteItemList(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + if (lua_isnumber(L, 2)) + { + kartitems_t item = luaL_checkinteger(L, 2); + K_PushToRouletteItemList(itemRoulette, item); + } + else if (lua_istable(L, 2)) + { + luaL_checktype(L, 2, LUA_TTABLE); + size_t size = luaL_getn(L, 2); + + for (size_t i = 1; i <= size; i++) + { + lua_rawgeti(L, 2, i); + if (lua_isnumber(L, -1)) + { + kartitems_t item = luaL_checkinteger(L, -1); + K_PushToRouletteItemList(itemRoulette, item); + } + else // Quit early, let the scripter know they messed up. + { + lua_pop(L, 1); + return luaL_error(L, "Non-integer value in table in index %d.", i); + } + lua_pop(L, 1); + } + } + else return LUA_ErrInvalid(L, "integer/table"); + + return 0; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4371,6 +4493,8 @@ static luaL_Reg lib[] = { {"K_ItemEnabled", lib_kItemEnabled}, {"K_ItemSingularity", lib_kItemSingularity}, {"K_GetBotItemPriority", lib_kGetBotItemPriority}, + {"K_AddItemToReel", lib_kAddItemToReel}, + {"K_PushToRouletteItemList", lib_kPushToRouletteItemList}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From 7d0a0a61c3a8431978795623bd083523a7170cc6 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 20 Oct 2024 20:19:12 +0200 Subject: [PATCH 08/46] Expose K_StartItemRoulette, K_StartEggmanRoulette and K_StopRoulette to Lua --- src/lua_baselib.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b7fbbdc86..27549c3a0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4203,6 +4203,46 @@ static int lib_kPushToRouletteItemList(lua_State *L) return 0; } +static int lib_kStartItemRoulette(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + boolean ringbox = lua_optboolean(L, 2); + + NOHUD + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + K_StartItemRoulette(player, ringbox); + return 0; +} + +static int lib_kStartEggmanRoulette(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + + NOHUD + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + K_StartEggmanRoulette(player); + return 0; +} + +static int lib_kStopRoulette(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + + NOHUD + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + K_StopRoulette(&player->itemRoulette); + return 0; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4495,6 +4535,9 @@ static luaL_Reg lib[] = { {"K_GetBotItemPriority", lib_kGetBotItemPriority}, {"K_AddItemToReel", lib_kAddItemToReel}, {"K_PushToRouletteItemList", lib_kPushToRouletteItemList}, + {"K_StartItemRoulette", lib_kStartItemRoulette}, + {"K_StartEggmanRoulette", lib_kStartEggmanRoulette}, + {"K_StopRoulette", lib_kStopRoulette}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From 0613c1ee9969884933ec37b49fae5559d8f85d5d Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 20 Oct 2024 20:36:48 +0200 Subject: [PATCH 09/46] Expose K_GetShieldFromItem to Lua --- src/lua_baselib.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 27549c3a0..a75b03125 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3923,6 +3923,14 @@ static int lib_kGetItemPatch(lua_State *L) return 1; } +static int lib_kGetShieldFromItem(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + //HUDSAFE + lua_pushinteger(L, K_GetShieldFromItem(item)); + return 1; +} + static int lib_kGetCollideAngle(lua_State *L) { mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -4512,9 +4520,9 @@ static luaL_Reg lib[] = { {"K_GetKartAccel",lib_kGetKartAccel}, {"K_GetKartFlashing",lib_kGetKartFlashing}, {"K_GetItemPatch",lib_kGetItemPatch}, - {"K_GetCollideAngle",lib_kGetCollideAngle}, {"K_AddHitLag",lib_kAddHitLag}, + {"K_GetShieldFromItem",lib_kGetShieldFromItem}, // k_powerup {"K_PowerUpRemaining",lib_kPowerUpRemaining}, From 73ad210e4e04478019362f5a0d256b3cbbe8acfd Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 20 Oct 2024 20:59:18 +0200 Subject: [PATCH 10/46] Expose K_GetItemCooldown and K_SetItemCooldown to Lua --- src/lua_baselib.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index a75b03125..63d2e6adf 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3931,6 +3931,45 @@ static int lib_kGetShieldFromItem(lua_State *L) return 1; } +static int lib_kItemResultToType(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + //HUDSAFE + lua_pushinteger(L, K_ItemResultToType(item)); + return 1; +} + +static int lib_kItemResultToAmount(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + //HUDSAFE + lua_pushinteger(L, K_ItemResultToAmount(item)); + return 1; +} + +static int lib_kGetItemCooldown(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + + NOHUD + INLEVEL + + lua_pushinteger(L, K_GetItemCooldown(item)); + return 1; +} + +static int lib_kSetItemCooldown(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + tic_t time = luaL_checkinteger(L, 2); + + NOHUD + INLEVEL + + K_SetItemCooldown(item, time); + return 0; +} + static int lib_kGetCollideAngle(lua_State *L) { mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -4523,6 +4562,10 @@ static luaL_Reg lib[] = { {"K_GetCollideAngle",lib_kGetCollideAngle}, {"K_AddHitLag",lib_kAddHitLag}, {"K_GetShieldFromItem",lib_kGetShieldFromItem}, + {"K_ItemResultToType",lib_kItemResultToType}, + {"K_ItemResultToAmount",lib_kItemResultToAmount}, + {"K_GetItemCooldown",lib_kGetItemCooldown}, + {"K_SetItemCooldown",lib_kSetItemCooldown}, // k_powerup {"K_PowerUpRemaining",lib_kPowerUpRemaining}, From ae11db8b7838b1ce24368632c7c7cbf536366a59 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 20 Oct 2024 21:13:25 +0200 Subject: [PATCH 11/46] Expose K_TimeAttackRules and K_CapsuleTimeAttackRules to Lua --- src/lua_baselib.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 63d2e6adf..0d8d4d404 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3970,6 +3970,21 @@ static int lib_kSetItemCooldown(lua_State *L) return 0; } +static int lib_kTimeAttackRules(lua_State *L) +{ + //HUDSAFE + lua_pushboolean(L, K_TimeAttackRules()); + return 1; +} + +static int lib_kCapsuleTimeAttackRules(lua_State *L) +{ + //HUDSAFE + lua_pushboolean(L, K_CapsuleTimeAttackRules()); + return 1; +} + + static int lib_kGetCollideAngle(lua_State *L) { mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -4566,6 +4581,8 @@ static luaL_Reg lib[] = { {"K_ItemResultToAmount",lib_kItemResultToAmount}, {"K_GetItemCooldown",lib_kGetItemCooldown}, {"K_SetItemCooldown",lib_kSetItemCooldown}, + {"K_TimeAttackRules",lib_kTimeAttackRules}, + {"K_CapsuleTimeAttackRules",lib_kCapsuleTimeAttackRules}, // k_powerup {"K_PowerUpRemaining",lib_kPowerUpRemaining}, From a4a6c349b4ed69ccbbd30616d4f254c813c9410e Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 26 Oct 2024 17:59:05 +0200 Subject: [PATCH 12/46] Expose K_KartGetItemResult to Lua --- src/k_roulette.c | 14 +++----------- src/k_roulette.h | 18 ++++++++++++++++++ src/lua_baselib.c | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 9604347e0..b1d69c796 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1845,19 +1845,11 @@ fixed_t K_GetSlotOffset(itemroulette_t *const roulette, fixed_t renderDelta, UIN } /*-------------------------------------------------- - static void K_KartGetItemResult(player_t *const player, kartitems_t getitem) + void K_KartGetItemResult(player_t *const player, kartitems_t getitem) - Initializes a player's item to what was - received from the roulette. - - Input Arguments:- - player - The player receiving the item. - getitem - The item to give to the player. - - Return:- - N/A + See header file for description. --------------------------------------------------*/ -static void K_KartGetItemResult(player_t *const player, kartitems_t getitem) +void K_KartGetItemResult(player_t *const player, kartitems_t getitem) { if (K_ItemSingularity(getitem) == true) { diff --git a/src/k_roulette.h b/src/k_roulette.h index fba9ef9f6..22c1bf273 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -260,6 +260,24 @@ fixed_t K_GetSlotOffset(itemroulette_t *const roulette, fixed_t renderDelta, UIN void K_KartItemRoulette(player_t *const player, ticcmd_t *cmd); +/*-------------------------------------------------- + void K_CreateAndShuffleItemReel(player_t *const player, itemroulette_t *const roulette, const boolean freeplay); + + Adds items to the item reel based on the RNG seed, + item odds or whether it's free play or not. + + Input Arguments:- + player - The player to add items to their reel to. + roulette - The player's roulette. + freeplay - Whether we should create the free play + roulette instead or not. + + Return:- + N/A +--------------------------------------------------*/ + +void K_KartGetItemResult(player_t *const player, kartitems_t getitem); + UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers); #ifdef __cplusplus diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 0d8d4d404..8ec941871 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4305,6 +4305,20 @@ static int lib_kStopRoulette(lua_State *L) return 0; } +static int lib_kKartGetItemResult(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + kartitems_t item = luaL_checkinteger(L, 2); + + NOHUD + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + K_KartGetItemResult(player, item); + return 0; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4606,6 +4620,7 @@ static luaL_Reg lib[] = { {"K_StartItemRoulette", lib_kStartItemRoulette}, {"K_StartEggmanRoulette", lib_kStartEggmanRoulette}, {"K_StopRoulette", lib_kStopRoulette}, + {"K_KartGetItemResult", lib_kKartGetItemResult}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From 44d58489189796dfba25313285a47193fd3841a0 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 26 Oct 2024 19:02:50 +0200 Subject: [PATCH 13/46] Expose FillItemRoulette hook for Lua --- src/k_roulette.c | 24 +++++++++++++++++++++++- src/lua_hook.h | 2 ++ src/lua_hooklib.c | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index b1d69c796..6a22f2269 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1208,12 +1208,23 @@ static boolean K_TimingPermitsItem(kartitems_t item, const itemroulette_t *roule return true; } +static void K_LuaHookItemRoulette(player_t *player, itemroulette_t *const roulette) +{ + // Lua can override the final result. + LUA_HookFillItemRoulette(player, roulette); + + // If somehow there's no items, add sad. + if (roulette->itemList.len == 0) { + K_AddItemToReel(player, roulette, KITEM_SAD); + } +} + /*-------------------------------------------------- void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun) See header file for description. --------------------------------------------------*/ -void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun) +void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun) { UINT32 spawnChance[NUMKARTRESULTS] = {0}; UINT32 totalSpawnChance = 0; @@ -1261,6 +1272,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet K_PushToRouletteItemList(roulette, presetlist[i]); } + K_LuaHookItemRoulette(player, roulette); return; } @@ -1269,6 +1281,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet if (cv_kartdebugitem.value != KITEM_NONE) { K_PushToRouletteItemList(roulette, cv_kartdebugitem.value); + K_LuaHookItemRoulette(player, roulette); return; } @@ -1282,6 +1295,8 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet { K_PushToRouletteItemList(roulette, K_KartItemReelSpecialEnd[i]); } + + K_LuaHookItemRoulette(player, roulette); return; } } @@ -1292,6 +1307,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet K_PushToRouletteItemList(roulette, K_KartItemReelBoss[i]); } + K_LuaHookItemRoulette(player, roulette); return; } else if (K_TimeAttackRules() == true) @@ -1358,6 +1374,8 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet } } + K_LuaHookItemRoulette(player, roulette); + return; } @@ -1366,6 +1384,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet if (K_ForcedSPB(player, roulette) == true) { K_AddItemToReel(player, roulette, KITEM_SPB); + K_LuaHookItemRoulette(player, roulette); return; } @@ -1390,6 +1409,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet // singleItem = KITEM_SAD by default, // so it will be used when all items are turned off. K_AddItemToReel(player, roulette, singleItem); + K_LuaHookItemRoulette(player, roulette); return; } @@ -1745,6 +1765,8 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet totalSpawnChance--; } + + K_LuaHookItemRoulette(player, roulette); } /*-------------------------------------------------- diff --git a/src/lua_hook.h b/src/lua_hook.h index 1f392d868..c9242d1fd 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -80,6 +80,7 @@ automatically. X (PlayerCmd),/* building the player's ticcmd struct */\ X (VoteThinker),/* Y_VoteTicker */\ X (PreFillItemRoulette),/* K_FillItemRouletteData, before special conditions but after roulette speed calc */\ + X (FillItemRoulette),/* K_FillItemRouletteData, right at the end */\ #define STRING_HOOK_LIST(X) \ X (SpecialExecute),\ @@ -148,6 +149,7 @@ void LUA_HookPlayerQuit(player_t *, kickreason_t); int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend); int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); +int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette); #ifdef __cplusplus } // extern "C" diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 0d1771f74..5447276f8 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1039,4 +1039,9 @@ int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette return roulette_hook(player, roulette, ringbox, HOOK(PreFillItemRoulette), res_true); } +int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette) +{ + return roulette_hook(player, roulette, false, HOOK(FillItemRoulette), res_true); +} + boolean hook_cmd_running = false; From 4694430292dee869ccc5fd247a3093c165c5575b Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 4 Jul 2025 15:43:16 -0400 Subject: [PATCH 14/46] Internal merge lua roulette fixup hell --- src/k_roulette.h | 4 ++-- src/lua_baselib.c | 3 ++- src/lua_itemroulettelib.c | 8 -------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/k_roulette.h b/src/k_roulette.h index 22c1bf273..7af1b98d8 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -134,7 +134,7 @@ INT32 K_KartGetBattleOdds(const player_t *player, UINT8 pos, kartitems_t item); /*-------------------------------------------------- - void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun); + void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun); Fills out the item roulette struct when it is initially created. This function needs to be @@ -152,7 +152,7 @@ INT32 K_KartGetBattleOdds(const player_t *player, UINT8 pos, kartitems_t item); N/A --------------------------------------------------*/ -void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun); +void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun); /*-------------------------------------------------- diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 8ec941871..911edcc7d 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3942,8 +3942,9 @@ static int lib_kItemResultToType(lua_State *L) static int lib_kItemResultToAmount(lua_State *L) { kartitems_t item = luaL_checkinteger(L, 1); + itemroulette_t *roulette = *((itemroulette_t **)luaL_checkudata(L, 2, META_ITEMROULETTE)); //HUDSAFE - lua_pushinteger(L, K_ItemResultToAmount(item)); + lua_pushinteger(L, K_ItemResultToAmount(item, roulette)); return 1; } diff --git a/src/lua_itemroulettelib.c b/src/lua_itemroulettelib.c index fa7b5e251..99da76fc3 100644 --- a/src/lua_itemroulettelib.c +++ b/src/lua_itemroulettelib.c @@ -26,7 +26,6 @@ enum itemroulette { itemroulette_valid = 0, itemroulette_active, itemroulette_itemlist, - itemroulette_useodds, itemroulette_playing, itemroulette_exiting, itemroulette_dist, @@ -48,7 +47,6 @@ static const char *const itemroulette_opt[] = { "valid", "active", "itemlist", - "useodds", "playing", "exiting", "dist", @@ -87,9 +85,6 @@ static int itemroulette_get(lua_State *L) case itemroulette_itemlist: LUA_PushUserdata(L, &itemroulette->itemList, META_ITEMROULETTE_ITEMLIST); break; - case itemroulette_useodds: - lua_pushinteger(L, itemroulette->useOdds); - break; case itemroulette_playing: lua_pushinteger(L, itemroulette->playing); break; @@ -171,9 +166,6 @@ static int itemroulette_set(lua_State *L) break; case itemroulette_itemlist: return NOSETITEMLIST; - case itemroulette_useodds: - itemroulette->useOdds = luaL_checkinteger(L, 3); - break; case itemroulette_playing: itemroulette->playing = luaL_checkinteger(L, 3); break; From 5a62e902a0019c1f8acc15c8e1313c4fb1dd9b91 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 26 Oct 2024 19:52:20 +0200 Subject: [PATCH 15/46] Expose K_GetItemRouletteDistance, K_FindUseodds and K_CreateAndShuffleItemReel to Lua --- src/k_roulette.c | 10 +--------- src/k_roulette.h | 30 ++++++++++++++++++++++++++++++ src/lua_baselib.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 6a22f2269..c5000f1f2 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -502,15 +502,7 @@ static UINT32 K_ScaleItemDistance(const player_t *player, UINT32 distance, UINT8 /*-------------------------------------------------- static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers) - Gets a player's distance used for the item - roulette, including all scaling factors. - - Input Arguments:- - player - The player to get the distance of. - numPlayers - Number of players in the game. - - Return:- - The player's finalized item distance. + See header file for description. --------------------------------------------------*/ UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers) { diff --git a/src/k_roulette.h b/src/k_roulette.h index 7af1b98d8..3d356f75a 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -278,8 +278,38 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *cmd); void K_KartGetItemResult(player_t *const player, kartitems_t getitem); +/*-------------------------------------------------- + static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers) + + Gets a player's distance used for the item + roulette, including all scaling factors. + + Input Arguments:- + player - The player to get the distance of. + numPlayers - Number of players in the game. + + Return:- + The player's finalized item distance. +--------------------------------------------------*/ + UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers); +/*-------------------------------------------------- + static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulette) + + Gets which item bracket the player is in. + This can be adjusted depending on which + items being turned off. + + Input Arguments:- + player - The player the roulette is for. + roulette - The item roulette data. + + Return:- + The item bracket the player is in, as an + index to the array. +--------------------------------------------------*/ + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 911edcc7d..6ca5fa891 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4320,6 +4320,36 @@ static int lib_kKartGetItemResult(lua_State *L) return 0; } +static int lib_kGetItemRouletteDistance(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + UINT8 numPlayers = luaL_checkinteger(L, 2); + INLEVEL + + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + lua_pushinteger(L, K_GetItemRouletteDistance(player, numPlayers)); + return 1; +} + +static int lib_kCreateAndShuffleItemReel(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + boolean freeplay = lua_optboolean(L, 2); + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + K_CreateAndShuffleItemReel(player, itemRoulette, freeplay); + return 0; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4622,6 +4652,9 @@ static luaL_Reg lib[] = { {"K_StartEggmanRoulette", lib_kStartEggmanRoulette}, {"K_StopRoulette", lib_kStopRoulette}, {"K_KartGetItemResult", lib_kKartGetItemResult}, + {"K_GetItemRouletteDistance", lib_kGetItemRouletteDistance}, + {"K_FindUseodds", lib_kFindUseodds}, + {"K_CreateAndShuffleItemReel", lib_kCreateAndShuffleItemReel}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From f32eefb9b5cf0445ab1a84a512ba2e75be046cfa Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 4 Jul 2025 15:48:10 -0400 Subject: [PATCH 16/46] Internal fuckup the third --- src/k_roulette.h | 32 -------------------------------- src/lua_baselib.c | 9 ++++----- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/src/k_roulette.h b/src/k_roulette.h index 3d356f75a..79d954c55 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -260,22 +260,6 @@ fixed_t K_GetSlotOffset(itemroulette_t *const roulette, fixed_t renderDelta, UIN void K_KartItemRoulette(player_t *const player, ticcmd_t *cmd); -/*-------------------------------------------------- - void K_CreateAndShuffleItemReel(player_t *const player, itemroulette_t *const roulette, const boolean freeplay); - - Adds items to the item reel based on the RNG seed, - item odds or whether it's free play or not. - - Input Arguments:- - player - The player to add items to their reel to. - roulette - The player's roulette. - freeplay - Whether we should create the free play - roulette instead or not. - - Return:- - N/A ---------------------------------------------------*/ - void K_KartGetItemResult(player_t *const player, kartitems_t getitem); /*-------------------------------------------------- @@ -294,22 +278,6 @@ void K_KartGetItemResult(player_t *const player, kartitems_t getitem); UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers); -/*-------------------------------------------------- - static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulette) - - Gets which item bracket the player is in. - This can be adjusted depending on which - items being turned off. - - Input Arguments:- - player - The player the roulette is for. - roulette - The item roulette data. - - Return:- - The item bracket the player is in, as an - index to the array. ---------------------------------------------------*/ - #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6ca5fa891..894fd3649 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4333,20 +4333,20 @@ static int lib_kGetItemRouletteDistance(lua_State *L) return 1; } -static int lib_kCreateAndShuffleItemReel(lua_State *L) +static int lib_kFillItemRouletteData(lua_State *L) { player_t *player = NULL; itemroulette_t *itemRoulette = NULL; getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); - boolean freeplay = lua_optboolean(L, 2); + boolean ringbox = lua_optboolean(L, 2); NOHUD INLEVEL if (!player && !itemRoulette) return LUA_ErrInvalid(L, "player_t/itemroulette_t"); - K_CreateAndShuffleItemReel(player, itemRoulette, freeplay); + K_FillItemRouletteData(player, itemRoulette, ringbox, false); return 0; } @@ -4653,8 +4653,7 @@ static luaL_Reg lib[] = { {"K_StopRoulette", lib_kStopRoulette}, {"K_KartGetItemResult", lib_kKartGetItemResult}, {"K_GetItemRouletteDistance", lib_kGetItemRouletteDistance}, - {"K_FindUseodds", lib_kFindUseodds}, - {"K_CreateAndShuffleItemReel", lib_kCreateAndShuffleItemReel}, + {"K_FillItemRouletteData", lib_kFillItemRouletteData}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From 3c3dec6a463cda23e2efd8ebc6f5b50c44ec5ce2 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sat, 26 Oct 2024 20:15:17 +0200 Subject: [PATCH 17/46] Create K_WipeItemsInReel for Lua --- src/lua_baselib.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 894fd3649..c459ce331 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4350,6 +4350,22 @@ static int lib_kFillItemRouletteData(lua_State *L) return 0; } +static int lib_kWipeItemsInReel(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + itemRoulette->itemList.len = 0; + return 0; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4654,6 +4670,9 @@ static luaL_Reg lib[] = { {"K_KartGetItemResult", lib_kKartGetItemResult}, {"K_GetItemRouletteDistance", lib_kGetItemRouletteDistance}, {"K_FillItemRouletteData", lib_kFillItemRouletteData}, + // These are not real functions in k_roulette, but they allow + // encapsulation on how the scripter interacts with the item reel. + {"K_WipeItemsInReel", lib_kWipeItemsInReel}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From 303df563c39bec833a75b9240e1c9e39b666c518 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 27 Oct 2024 02:46:37 +0100 Subject: [PATCH 18/46] Add K_SetItemInReelByIndex, K_AddItemToReelByIndex and K_RemoveItemFromReelByIndex to Lua --- src/lua_baselib.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c459ce331..8cbde0bc5 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4366,6 +4366,134 @@ static int lib_kWipeItemsInReel(lua_State *L) return 0; } +static int lib_kSetItemInReelByIndex(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + size_t index = luaL_checkinteger(L, 2) - 1; + kartitems_t item = luaL_checkinteger(L, 3); + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + if (itemRoulette->itemList.len == 0) + return luaL_error(L, "There are no items in the roulette to set."); + + if (index > itemRoulette->itemList.len - 1) + return luaL_error(L, "Roulette index %d out of bounds (should be between %d and %d).", index + 1, 1, itemRoulette->itemList.len); + + itemRoulette->itemList.items[index] = item; + return 0; +} + +static void AddOrPushToItemReel(player_t *player, itemroulette_t *roulette, kartitems_t item, boolean addRings) +{ + if (addRings) + K_AddItemToReel(player, roulette, item); + else + K_PushToRouletteItemList(roulette, item); +} + +static int lib_kAddItemToReelByIndex(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + size_t index = luaL_checkinteger(L, 2) - 1; + kartitems_t item = luaL_checkinteger(L, 3); + boolean addRings = lua_optboolean(L, 4); + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + // If the list is empty, just add the item silently and leave. + if (itemRoulette->itemList.len == 0) { + AddOrPushToItemReel(player, itemRoulette, item, addRings); + return 0; + } + + if (index > itemRoulette->itemList.len - 1) + return luaL_error(L, "Roulette index %d out of bounds (should be between %d and %d).", index + 1, 1, itemRoulette->itemList.len); + + size_t latterItemList = itemRoulette->itemList.len - index; + kartitems_t *latterItems = Z_Calloc( + sizeof(kartitems_t) * latterItemList, + PU_STATIC, + NULL + ); + + if (!latterItems) + I_Error("Out of memory during calloc for lib_kAddItemToReelByIndex."); + + for (size_t i = 0; i < latterItemList; i++) + { + latterItems[i] = itemRoulette->itemList.items[index + i]; + } + + itemRoulette->itemList.len = index; + AddOrPushToItemReel(player, itemRoulette, item, addRings); + + for (size_t i = 0; i < latterItemList; i++) + { + AddOrPushToItemReel(player, itemRoulette, latterItems[i], addRings); + } + + Z_Free(latterItems); + + return 0; +} + +static int lib_kRemoveItemFromReelByIndex(lua_State *L) +{ + player_t *player = NULL; + itemroulette_t *itemRoulette = NULL; + + getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); + size_t index = luaL_checkinteger(L, 2) - 1; + + NOHUD + INLEVEL + if (!player && !itemRoulette) + return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + + if (itemRoulette->itemList.len == 0) + return luaL_error(L, "There are no items in the roulette to delete."); + + if (index > itemRoulette->itemList.len - 1) + return luaL_error(L, "Roulette index %d out of bounds (should be between %d and %d).", index + 1, 1, itemRoulette->itemList.len); + + size_t latterItemList = itemRoulette->itemList.len - index - 1; + kartitems_t *latterItems = Z_Calloc( + sizeof(kartitems_t) * latterItemList, + PU_STATIC, + NULL + ); + + if (!latterItems) + I_Error("Out of memory during calloc for lib_kRemoveItemFromReelByIndex."); + + for (size_t i = 0; i < latterItemList; i++) + { + latterItems[i] = itemRoulette->itemList.items[index + 1 + i]; + } + + itemRoulette->itemList.len = index; + + for (size_t i = 0; i < latterItemList; i++) + K_PushToRouletteItemList(itemRoulette, latterItems[i]); + + Z_Free(latterItems); + + return 0; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4673,6 +4801,9 @@ static luaL_Reg lib[] = { // These are not real functions in k_roulette, but they allow // encapsulation on how the scripter interacts with the item reel. {"K_WipeItemsInReel", lib_kWipeItemsInReel}, + {"K_SetItemInReelByIndex", lib_kSetItemInReelByIndex}, + {"K_AddItemToReelByIndex", lib_kAddItemToReelByIndex}, + {"K_RemoveItemFromReelByIndex", lib_kRemoveItemFromReelByIndex}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From a6c34c4ff2e346ae644ff7c5a1e23b521d734320 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 27 Oct 2024 16:04:05 +0100 Subject: [PATCH 19/46] Expose K_ForcedSPB and K_DenyShieldOdds to Lua --- src/k_roulette.c | 27 +++++---------------------- src/k_roulette.h | 33 +++++++++++++++++++++++++++++++++ src/lua_baselib.c | 22 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index c5000f1f2..d2e10dc60 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -566,19 +566,11 @@ UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers) } /*-------------------------------------------------- - static boolean K_DenyShieldOdds(kartitems_t item) + boolean K_DenyShieldOdds(kartitems_t item) - Checks if this type of shield already exists in - another player's inventory. - - Input Arguments:- - item - The item type of the shield. - - Return:- - Whether this item is a shield and may not be awarded - at this time. + See header file for description. --------------------------------------------------*/ -static boolean K_DenyShieldOdds(kartitems_t item) +boolean K_DenyShieldOdds(kartitems_t item) { const INT32 shieldType = K_GetShieldFromItem(item); size_t i; @@ -691,18 +683,9 @@ INT32 K_KartGetBattleOdds(const player_t *player, UINT8 pos, kartitems_t item) /*-------------------------------------------------- static boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette) - Determines special conditions where we want - to forcefully give the player an SPB. - - Input Arguments:- - player - The player the roulette is for. - roulette - The item roulette data. - - Return:- - true if we want to give the player a forced SPB, - otherwise false. + See header file for description. --------------------------------------------------*/ -static boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette) +boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette) { if (K_ItemEnabled(KITEM_SPB) == false) { diff --git a/src/k_roulette.h b/src/k_roulette.h index 79d954c55..b105f1c90 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -278,6 +278,39 @@ void K_KartGetItemResult(player_t *const player, kartitems_t getitem); UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers); +/*-------------------------------------------------- + boolean K_DenyShieldOdds(kartitems_t item) + + Checks if this type of shield already exists in + another player's inventory. + + Input Arguments:- + item - The item type of the shield. + + Return:- + Whether this item is a shield and may not be awarded + at this time. +--------------------------------------------------*/ + +boolean K_DenyShieldOdds(kartitems_t item); + +/*-------------------------------------------------- + boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette) + + Determines special conditions where we want + to forcefully give the player an SPB. + + Input Arguments:- + player - The player the roulette is for. + roulette - The item roulette data. + + Return:- + true if we want to give the player a forced SPB, + otherwise false. +--------------------------------------------------*/ + +boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 8cbde0bc5..b6fc6b4c0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4350,6 +4350,26 @@ static int lib_kFillItemRouletteData(lua_State *L) return 0; } +static int lib_kForcedSPB(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + INLEVEL + + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + lua_pushboolean(L, K_ForcedSPB(player, &player->itemRoulette)); + return 1; +} + +static int lib_kDenyShieldOdds(lua_State *L) +{ + kartitems_t item = luaL_checkinteger(L, 1); + INLEVEL + lua_pushboolean(L, K_DenyShieldOdds(item)); + return 1; +} + static int lib_kWipeItemsInReel(lua_State *L) { player_t *player = NULL; @@ -4798,6 +4818,8 @@ static luaL_Reg lib[] = { {"K_KartGetItemResult", lib_kKartGetItemResult}, {"K_GetItemRouletteDistance", lib_kGetItemRouletteDistance}, {"K_FillItemRouletteData", lib_kFillItemRouletteData}, + {"K_ForcedSPB", lib_kForcedSPB}, + {"K_DenyShieldOdds", lib_kDenyShieldOdds}, // These are not real functions in k_roulette, but they allow // encapsulation on how the scripter interacts with the item reel. {"K_WipeItemsInReel", lib_kWipeItemsInReel}, From 6359cf19b7adec12c279201e086a554eab77f7df Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 27 Oct 2024 16:32:19 +0100 Subject: [PATCH 20/46] Expose K_GetRouletteOffset and K_GetSlotOffset to Lua --- src/lua_baselib.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b6fc6b4c0..f08435037 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4370,6 +4370,34 @@ static int lib_kDenyShieldOdds(lua_State *L) return 1; } +static int lib_kGetRouletteOffset(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + fixed_t renderDelta = luaL_optnumber(L, 2, FRACUNIT); + UINT8 fudge = luaL_optnumber(L, 3, player ? player->cmd.latency : 0); + INLEVEL + + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + lua_pushfixed(L, K_GetRouletteOffset(&player->itemRoulette, renderDelta, fudge)); + return 1; +} + +static int lib_kGetSlotOffset(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + fixed_t renderDelta = luaL_optnumber(L, 2, FRACUNIT); + UINT8 fudge = luaL_optnumber(L, 3, player ? player->cmd.latency : 0); + INLEVEL + + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + lua_pushfixed(L, K_GetSlotOffset(&player->itemRoulette, renderDelta, fudge)); + return 1; +} + static int lib_kWipeItemsInReel(lua_State *L) { player_t *player = NULL; @@ -4820,6 +4848,8 @@ static luaL_Reg lib[] = { {"K_FillItemRouletteData", lib_kFillItemRouletteData}, {"K_ForcedSPB", lib_kForcedSPB}, {"K_DenyShieldOdds", lib_kDenyShieldOdds}, + {"K_GetRouletteOffset", lib_kGetRouletteOffset}, + {"K_GetSlotOffset", lib_kGetSlotOffset}, // These are not real functions in k_roulette, but they allow // encapsulation on how the scripter interacts with the item reel. {"K_WipeItemsInReel", lib_kWipeItemsInReel}, From 501c85a7b19ddac58207261e8f2f5784d4010e71 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 27 Oct 2024 16:45:29 +0100 Subject: [PATCH 21/46] Expose K_CalculateRouletteSpeed to Lua --- src/k_roulette.c | 14 +++----------- src/k_roulette.h | 16 ++++++++++++++++ src/lua_baselib.c | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index d2e10dc60..6bec64905 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -897,19 +897,11 @@ void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kar } /*-------------------------------------------------- - static void K_CalculateRouletteSpeed(itemroulette_t *const roulette) + void K_CalculateRouletteSpeed(itemroulette_t *const roulette) - Determines the speed for the item roulette, - adjusted for progress in the race and front - running. - - Input Arguments:- - roulette - The item roulette data to modify. - - Return:- - N/A + See header file for description. --------------------------------------------------*/ -static void K_CalculateRouletteSpeed(itemroulette_t *const roulette) +void K_CalculateRouletteSpeed(itemroulette_t *const roulette) { fixed_t frontRun = 0; fixed_t progress = 0; diff --git a/src/k_roulette.h b/src/k_roulette.h index b105f1c90..e61fb7a97 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -113,6 +113,22 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item); void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item); +/*-------------------------------------------------- + void K_CalculateRouletteSpeed(itemroulette_t *const roulette) + + Determines the speed for the item roulette, + adjusted for progress in the race and front + running. + + Input Arguments:- + roulette - The item roulette data to modify. + + Return:- + N/A +--------------------------------------------------*/ + +void K_CalculateRouletteSpeed(itemroulette_t *const roulette); + /*-------------------------------------------------- INT32 K_KartGetBattleOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index f08435037..7070be288 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4398,6 +4398,19 @@ static int lib_kGetSlotOffset(lua_State *L) return 1; } +static int lib_kCalculateRouletteSpeed(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + + NOHUD + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + + K_CalculateRouletteSpeed(&player->itemRoulette); + return 0; +} + static int lib_kWipeItemsInReel(lua_State *L) { player_t *player = NULL; @@ -4850,6 +4863,7 @@ static luaL_Reg lib[] = { {"K_DenyShieldOdds", lib_kDenyShieldOdds}, {"K_GetRouletteOffset", lib_kGetRouletteOffset}, {"K_GetSlotOffset", lib_kGetSlotOffset}, + {"K_CalculateRouletteSpeed", lib_kCalculateRouletteSpeed}, // These are not real functions in k_roulette, but they allow // encapsulation on how the scripter interacts with the item reel. {"K_WipeItemsInReel", lib_kWipeItemsInReel}, From bf278f4fcc06b8b93e2445c5548487288da0fe52 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 27 Oct 2024 17:08:11 +0100 Subject: [PATCH 22/46] Expose K_ScaleItemDistance and K_ItemOddsScale to Lua --- src/k_roulette.c | 25 ++++++------------------- src/k_roulette.h | 32 ++++++++++++++++++++++++++++++++ src/lua_baselib.c | 17 +++++++++++++++++ 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 6bec64905..bac0b1e71 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -399,17 +399,9 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result) /*-------------------------------------------------- static fixed_t K_ItemOddsScale(UINT8 playerCount) - A multiplier for odds and distances to scale - them with the player count. - - Input Arguments:- - playerCount - Number of players in the game. - - Return:- - Fixed point number, to multiply odds or - distances by. + See header file for description. --------------------------------------------------*/ -static fixed_t K_ItemOddsScale(UINT8 playerCount) +fixed_t K_ItemOddsScale(UINT8 playerCount) { const UINT8 basePlayer = 8; // The player count we design most of the game around. fixed_t playerScaling = 0; @@ -462,7 +454,7 @@ static UINT32 K_UndoMapScaling(UINT32 distance) } /*-------------------------------------------------- - static UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) + UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) Adjust item distance for lobby-size scaling as well as Frantic Items. @@ -475,10 +467,8 @@ static UINT32 K_UndoMapScaling(UINT32 distance) Return:- New distance after scaling. --------------------------------------------------*/ -static UINT32 K_ScaleItemDistance(const player_t *player, UINT32 distance, UINT8 numPlayers) +UINT32 K_ScaleItemDistance(INT32 distance, UINT8 numPlayers) { - (void)player; - #if 0 if (franticitems == true) { @@ -493,9 +483,6 @@ static UINT32 K_ScaleItemDistance(const player_t *player, UINT32 distance, UINT8 FRACUNIT + (K_ItemOddsScale(numPlayers) / 2) ); - // Distance is reduced based on the player's gradingfactor - // distance = FixedMul(distance, player->gradingfactor); - return distance; } @@ -554,7 +541,7 @@ UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers) } pdis = K_UndoMapScaling(pdis); - pdis = K_ScaleItemDistance(player, pdis, numPlayers); + pdis = K_ScaleItemDistance(pdis, numPlayers); if (player->bot && (player->botvars.rival || cv_levelskull.value)) { @@ -830,7 +817,7 @@ static void K_InitRoulette(itemroulette_t *const roulette) && roulette->secondDist > roulette->firstDist) { roulette->secondToFirst = roulette->secondDist - roulette->firstDist; - roulette->secondToFirst = K_ScaleItemDistance(&players[i], roulette->secondToFirst, 16 - roulette->playing); // Reversed scaling + roulette->secondToFirst = K_ScaleItemDistance(roulette->secondToFirst, 16 - roulette->playing); // Reversed scaling } } diff --git a/src/k_roulette.h b/src/k_roulette.h index e61fb7a97..84356ea06 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -76,6 +76,38 @@ boolean K_ItemSingularity(kartitems_t item); botItemPriority_e K_GetBotItemPriority(kartitems_t result); +/*-------------------------------------------------- + fixed_t K_ItemOddsScale(UINT8 playerCount) + + A multiplier for odds and distances to scale + them with the player count. + + Input Arguments:- + playerCount - Number of players in the game. + + Return:- + Fixed point number, to multiply odds or + distances by. +--------------------------------------------------*/ + +fixed_t K_ItemOddsScale(UINT8 playerCount); + +/*-------------------------------------------------- + UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) + + Adjust item distance for lobby-size scaling + as well as Frantic Items. + + Input Arguments:- + distance - Original distance. + numPlayers - Number of players in the game. + + Return:- + New distance after scaling. +--------------------------------------------------*/ + +UINT32 K_ScaleItemDistance(INT32 distance, UINT8 numPlayers); + /*-------------------------------------------------- void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 7070be288..4fcb22622 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4411,6 +4411,21 @@ static int lib_kCalculateRouletteSpeed(lua_State *L) return 0; } +static int lib_kScaleItemDistance(lua_State *L) +{ + UINT32 distance = luaL_checkinteger(L, 1); + UINT8 numPlayers = luaL_checkinteger(L, 2); + lua_pushfixed(L, K_ScaleItemDistance(distance, numPlayers)); + return 1; +} + +static int lib_kItemOddsScale(lua_State *L) +{ + UINT8 playerCount = luaL_checkinteger(L, 1); + lua_pushfixed(L, K_ItemOddsScale(playerCount)); + return 1; +} + static int lib_kWipeItemsInReel(lua_State *L) { player_t *player = NULL; @@ -4864,6 +4879,8 @@ static luaL_Reg lib[] = { {"K_GetRouletteOffset", lib_kGetRouletteOffset}, {"K_GetSlotOffset", lib_kGetSlotOffset}, {"K_CalculateRouletteSpeed", lib_kCalculateRouletteSpeed}, + {"K_ScaleItemDistance", lib_kScaleItemDistance}, + {"K_ItemOddsScale", lib_kItemOddsScale}, // These are not real functions in k_roulette, but they allow // encapsulation on how the scripter interacts with the item reel. {"K_WipeItemsInReel", lib_kWipeItemsInReel}, From b2fae10b481dc396743aa6b1df4f39254d89f328 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Sun, 27 Oct 2024 17:19:22 +0100 Subject: [PATCH 23/46] Expose K_CheckBossIntro and K_CanChangeRules to Lua --- src/lua_baselib.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 4fcb22622..8c891c335 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -32,6 +32,7 @@ #include "k_collide.h" #include "k_color.h" #include "k_hud.h" +#include "k_grandprix.h" #include "d_netcmd.h" // IsPlayerAdmin #include "k_menu.h" // Player Setup menu color stuff #include "p_spec.h" // P_StartQuake @@ -4080,6 +4081,12 @@ static int lib_kDeclareWeakspot(lua_State *L) return 0; } +static int lib_kCheckBossIntro(lua_State *L) +{ + lua_pushboolean(L, K_CheckBossIntro()); + return 1; +} + static int lib_vsGetArena(lua_State *L) { INT32 bossindex = luaL_checkinteger(L, 1); @@ -4570,6 +4577,12 @@ static int lib_kRemoveItemFromReelByIndex(lua_State *L) return 0; } +static int lib_kCanChangeRules(lua_State *L) +{ + lua_pushboolean(L, K_CanChangeRules(true)); + return 1; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4858,6 +4871,7 @@ static luaL_Reg lib[] = { {"K_InitBossHealthBar", lib_kInitBossHealthBar}, {"K_UpdateBossHealthBar", lib_kUpdateBossHealthBar}, {"K_DeclareWeakspot", lib_kDeclareWeakspot}, + {"K_CheckBossIntro", lib_kCheckBossIntro}, {"VS_GetArena", lib_vsGetArena}, {"VS_PredictAroundArena", lib_vsPredictAroundArena}, {"VS_RandomPointOnArena", lib_vsRandomPointOnArena}, @@ -4888,6 +4902,9 @@ static luaL_Reg lib[] = { {"K_AddItemToReelByIndex", lib_kAddItemToReelByIndex}, {"K_RemoveItemFromReelByIndex", lib_kRemoveItemFromReelByIndex}, + // k_grandprix + {"K_CanChangeRules", lib_kCanChangeRules}, + // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, From 753657bd367fbc0f9c315cda38168139d2502768 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Fri, 1 Nov 2024 17:44:22 +0100 Subject: [PATCH 24/46] Comment out ITEM_LIST_SIZE, Fix CheckHeap crash on item roulette (re)alloc. Also change the default item cap to 32, since the free item roulette makes it go up to 30, avoiding a bunch of unneeded reallocs. --- src/d_player.h | 6 +++--- src/k_roulette.c | 6 +++--- src/p_saveg.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 9a4f42f9e..3178c76df 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -506,9 +506,9 @@ struct skybox_t { }; // player_t struct for item roulette variables -// Doing this the right way is causing problems. -// so FINE, it's a static length now. -#define ITEM_LIST_SIZE (NUMKARTRESULTS << 3) + +// In case of dynamic alloc failure, break glass: +// #define ITEM_LIST_SIZE (NUMKARTRESULTS << 3) typedef struct itemlist_t { diff --git a/src/k_roulette.c b/src/k_roulette.c index bac0b1e71..1850de449 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -737,11 +737,11 @@ static void K_InitRoulette(itemroulette_t *const roulette) #ifndef ITEM_LIST_SIZE if (roulette->itemList.items == NULL) { - roulette->itemList.cap = 8; + roulette->itemList.cap = 32; roulette->itemList.items = Z_Calloc( sizeof(SINT8) * roulette->itemList.cap, PU_STATIC, - &roulette->itemList.items + NULL ); if (roulette->itemList.items == NULL) @@ -844,7 +844,7 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) roulette->itemList.items, sizeof(SINT8) * roulette->itemList.cap, PU_STATIC, - &roulette->itemList.items + NULL ); if (roulette->itemList.items == NULL) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index fe8f3045d..62c661e9b 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1452,7 +1452,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].itemRoulette.itemList.items = Z_Calloc( sizeof(SINT8) * players[i].itemRoulette.itemList.cap, PU_STATIC, - &players[i].itemRoulette.itemList.items + NULL ); } else @@ -1461,7 +1461,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].itemRoulette.itemList.items, sizeof(SINT8) * players[i].itemRoulette.itemList.cap, PU_STATIC, - &players[i].itemRoulette.itemList.items + NULL ); } From 4d14f76e16637f2c97f1c9af9f7717831ac6ddd9 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Mon, 17 Feb 2025 01:41:29 +0100 Subject: [PATCH 25/46] Expose IF_ flags to Lua --- src/deh_tables.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 8caad3c35..775d43e5c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5234,6 +5234,12 @@ struct int_const_s const INT_CONST[] = { {"KSM_SEVEN", KSM_SEVEN}, {"KSM_JACKPOT", KSM_JACKPOT}, {"KSM__MAX", KSM__MAX}, + + // itemflags_t + {"IF_USERINGS", IF_USERINGS}, + {"IF_ITEMOUT", IF_ITEMOUT}, + {"IF_EGGMANOUT", IF_EGGMANOUT}, + {"IF_HOLDREADY", IF_HOLDREADY}, // kartshields_t {"KSHIELD_NONE",KSHIELD_NONE}, From b08281627859777ddca77feb711cc535e6b5d394 Mon Sep 17 00:00:00 2001 From: JugadorXEI Date: Wed, 12 Mar 2025 14:16:14 +0100 Subject: [PATCH 26/46] Invalidate player.itemroulette.itemlist in LUA_InvalidatePlayer when applicable --- src/lua_itemroulettelib.c | 3 +++ src/lua_script.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/lua_itemroulettelib.c b/src/lua_itemroulettelib.c index 99da76fc3..51bd651f8 100644 --- a/src/lua_itemroulettelib.c +++ b/src/lua_itemroulettelib.c @@ -227,6 +227,9 @@ static int itemrouletteitemlist_get(lua_State *L) { itemlist_t *itemlist = *((itemlist_t **)luaL_checkudata(L, 1, META_ITEMROULETTE_ITEMLIST)); size_t index = luaL_checkint(L, 2); + + if (!itemlist) + return LUA_ErrInvalid(L, "itemroulette_t.itemlist_t"); if (index == 0 || index > itemlist->len) { return luaL_error(L, LUA_QL("itemroulette_t.itemlist_t") " index cannot be %d", index); diff --git a/src/lua_script.c b/src/lua_script.c index cda71ff13..f70c93a2a 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -892,6 +892,7 @@ void LUA_InvalidatePlayer(player_t *player) LUA_InvalidateUserdata(player); LUA_InvalidateUserdata(player->karthud); LUA_InvalidateUserdata(&player->cmd); + LUA_InvalidateUserdata(&player->itemRoulette.itemList); } enum From bed1feb1a0dd750b6698ea8cc7d30941de57de38 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 4 Jul 2025 16:40:48 -0400 Subject: [PATCH 27/46] 2.4 Lua roulette fixup FINAL? --- src/k_roulette.c | 14 -------------- src/lua_hook.h | 2 -- src/lua_hooklib.c | 5 ----- src/p_saveg.cpp | 4 ++-- 4 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 1850de449..7a2c46f59 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1201,20 +1201,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo K_CalculateRouletteSpeed(roulette); } - // The roulette should be init'd first, and the speed should be - // set if applicable before you can override anything. - { - if (LUA_HookPreFillItemRoulette(player, roulette, ringbox)) - { - // If somehow there's no items, add sad. - if (roulette->itemList.len == 0) { - K_AddItemToReel(player, roulette, KITEM_SAD); - } - return; - } - - } - if (ringbox == true) { // If this is being invoked by a Ring Box, it should literally never produce items. diff --git a/src/lua_hook.h b/src/lua_hook.h index c9242d1fd..b4ec2b24a 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -79,7 +79,6 @@ automatically. X (GameQuit),\ X (PlayerCmd),/* building the player's ticcmd struct */\ X (VoteThinker),/* Y_VoteTicker */\ - X (PreFillItemRoulette),/* K_FillItemRouletteData, before special conditions but after roulette speed calc */\ X (FillItemRoulette),/* K_FillItemRouletteData, right at the end */\ #define STRING_HOOK_LIST(X) \ @@ -148,7 +147,6 @@ void LUA_HookPlayerQuit(player_t *, kickreason_t); //int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend); -int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette); #ifdef __cplusplus diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 5447276f8..b751f75ee 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1034,11 +1034,6 @@ static int roulette_hook( return hook.status; } -int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox) -{ - return roulette_hook(player, roulette, ringbox, HOOK(PreFillItemRoulette), res_true); -} - int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette) { return roulette_hook(player, roulette, false, HOOK(FillItemRoulette), res_true); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 62c661e9b..5223005eb 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1449,7 +1449,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) { if (players[i].itemRoulette.itemList.items == NULL) { - players[i].itemRoulette.itemList.items = Z_Calloc( + players[i].itemRoulette.itemList.items = (SINT8*)Z_Calloc( sizeof(SINT8) * players[i].itemRoulette.itemList.cap, PU_STATIC, NULL @@ -1457,7 +1457,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) } else { - players[i].itemRoulette.itemList.items = Z_Realloc( + players[i].itemRoulette.itemList.items = (SINT8*)Z_Realloc( players[i].itemRoulette.itemList.items, sizeof(SINT8) * players[i].itemRoulette.itemList.cap, PU_STATIC, From 5dc72e98868a0cd59a061ba269c8ab77347bec58 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 5 Jul 2025 16:16:26 -0400 Subject: [PATCH 28/46] Restore PreFilItemRoulette by moving hooks outside of reelbuilder --- src/k_kart.c | 2 ++ src/k_roulette.c | 26 +++++++++++++------------- src/k_roulette.h | 18 ++++++++++++++++++ src/lua_baselib.c | 4 ++++ src/lua_hook.h | 4 +++- src/lua_hooklib.c | 6 ++++++ 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index c12b18e96..cf395cc50 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -145,6 +145,8 @@ boolean K_InRaceDuel(void) fixed_t K_EffectiveGradingFactor(const player_t *player) { + I_Assert(player != NULL); + fixed_t min = (franticitems) ? MINFRANTICFACTOR : MINGRADINGFACTOR; if (grandprixinfo.gp && grandprixinfo.masterbots && !K_PlayerUsesBotMovement(player)) return min; diff --git a/src/k_roulette.c b/src/k_roulette.c index 7a2c46f59..b76ee6bae 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1162,9 +1162,19 @@ static boolean K_TimingPermitsItem(kartitems_t item, const itemroulette_t *roule return true; } -static void K_LuaHookItemRoulette(player_t *player, itemroulette_t *const roulette) +void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, boolean ringbox) { - // Lua can override the final result. + // Lua may want to intercept reelbuilder entirely. + LUA_HookPreFillItemRoulette(player, roulette); + + // If prehook did something, no need to continue. + if (roulette->itemList.len != 0) { + return; + } + + K_FillItemRouletteData(player, roulette, ringbox, false); + + // Lua can modify the final result. LUA_HookFillItemRoulette(player, roulette); // If somehow there's no items, add sad. @@ -1212,7 +1222,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo K_PushToRouletteItemList(roulette, presetlist[i]); } - K_LuaHookItemRoulette(player, roulette); return; } @@ -1221,7 +1230,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo if (cv_kartdebugitem.value != KITEM_NONE) { K_PushToRouletteItemList(roulette, cv_kartdebugitem.value); - K_LuaHookItemRoulette(player, roulette); return; } @@ -1236,7 +1244,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo K_PushToRouletteItemList(roulette, K_KartItemReelSpecialEnd[i]); } - K_LuaHookItemRoulette(player, roulette); return; } } @@ -1247,7 +1254,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo K_PushToRouletteItemList(roulette, K_KartItemReelBoss[i]); } - K_LuaHookItemRoulette(player, roulette); return; } else if (K_TimeAttackRules() == true) @@ -1314,8 +1320,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo } } - K_LuaHookItemRoulette(player, roulette); - return; } @@ -1324,7 +1328,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo if (K_ForcedSPB(player, roulette) == true) { K_AddItemToReel(player, roulette, KITEM_SPB); - K_LuaHookItemRoulette(player, roulette); return; } @@ -1349,7 +1352,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo // singleItem = KITEM_SAD by default, // so it will be used when all items are turned off. K_AddItemToReel(player, roulette, singleItem); - K_LuaHookItemRoulette(player, roulette); return; } @@ -1705,8 +1707,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo totalSpawnChance--; } - - K_LuaHookItemRoulette(player, roulette); } /*-------------------------------------------------- @@ -1719,7 +1719,7 @@ void K_StartItemRoulette(player_t *const player, boolean ringbox) itemroulette_t *const roulette = &player->itemRoulette; size_t i; - K_FillItemRouletteData(player, roulette, ringbox, false); + K_FillItemRoulette(player, roulette, ringbox); if (roulette->autoroulette) roulette->index = P_RandomRange(PR_AUTOROULETTE, 0, roulette->itemList.len - 1); diff --git a/src/k_roulette.h b/src/k_roulette.h index 84356ea06..e45dd7809 100644 --- a/src/k_roulette.h +++ b/src/k_roulette.h @@ -180,6 +180,24 @@ void K_CalculateRouletteSpeed(itemroulette_t *const roulette); INT32 K_KartGetBattleOdds(const player_t *player, UINT8 pos, kartitems_t item); +/*-------------------------------------------------- + void K_FillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); + + Entry point for roulette builder. + Includes Lua hooks. + + Input Arguments:- + player - The player this roulette data is for. + Can be NULL for generic use. + roulette - The roulette data struct to fill out. + ringbox - Is this roulette fill triggered by a just-respawned Ring Box? + + Return:- + N/A +--------------------------------------------------*/ + +void K_FillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); + /*-------------------------------------------------- void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 8c891c335..435df1345 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4167,17 +4167,21 @@ static void getItemRouletteOrPlayerBasedOnFirstParam(lua_State *L, player_t **pl { if (lua_getmetatable(L, 1)) { + CONS_Printf("case A\n"); lua_getfield(L, LUA_REGISTRYINDEX, META_ITEMROULETTE); if (lua_rawequal(L, -1, -2)) { + CONS_Printf("case A2\n"); *itemRoulette = *(itemroulette_t **)p; } else { + CONS_Printf("case B\n"); lua_pop(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, META_PLAYER); if (lua_rawequal(L, -1, -2)) { + CONS_Printf("case B2\n"); *player = *(player_t **)p; *itemRoulette = &(*player)->itemRoulette; } diff --git a/src/lua_hook.h b/src/lua_hook.h index b4ec2b24a..8187cbaa7 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -79,7 +79,8 @@ automatically. X (GameQuit),\ X (PlayerCmd),/* building the player's ticcmd struct */\ X (VoteThinker),/* Y_VoteTicker */\ - X (FillItemRoulette),/* K_FillItemRouletteData, right at the end */\ + X (PreFillItemRoulette),/* K_FillItemRouletteData, before attempted reel build */\ + X (FillItemRoulette),/* K_FillItemRouletteData, after built reel is in place */\ #define STRING_HOOK_LIST(X) \ X (SpecialExecute),\ @@ -147,6 +148,7 @@ void LUA_HookPlayerQuit(player_t *, kickreason_t); //int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend); +int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette); int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette); #ifdef __cplusplus diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index b751f75ee..0d9b72cbe 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1034,6 +1034,12 @@ static int roulette_hook( return hook.status; } +int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette) +{ + return roulette_hook(player, roulette, false, HOOK(PreFillItemRoulette), res_true); +} + + int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette) { return roulette_hook(player, roulette, false, HOOK(FillItemRoulette), res_true); From 4ed4989f3bcac4edd8b10bae314650cc6b97ca47 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 5 Jul 2025 16:29:29 -0400 Subject: [PATCH 29/46] Remove optional call-by-roulette path to Lua roulette stuff (we need player info in scope for EXP!) --- src/k_kart.c | 3 +- src/lua_baselib.c | 104 +++++++++++++--------------------------------- 2 files changed, 32 insertions(+), 75 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index cf395cc50..555c3a793 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -145,7 +145,8 @@ boolean K_InRaceDuel(void) fixed_t K_EffectiveGradingFactor(const player_t *player) { - I_Assert(player != NULL); + if (player == NULL) + return FRACUNIT; // K_FillItemRouletteData can OSTENSIBLY call this with null player for "generic" use. fixed_t min = (franticitems) ? MINFRANTICFACTOR : MINGRADINGFACTOR; if (grandprixinfo.gp && grandprixinfo.masterbots && !K_PlayerUsesBotMovement(player)) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 435df1345..edb5fe556 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4151,57 +4151,16 @@ static int lib_kGetBotItemPriority(lua_State *L) return 1; } -static void getItemRouletteOrPlayerBasedOnFirstParam(lua_State *L, player_t **player, itemroulette_t **itemRoulette) -{ - /* - JugadorXEI @ 11/01/2024 (MM/DD/AAAA): - Ok, so. - I implemented luaL_testudata from Lua 5.2 because I wanted to test if an argument - was one userdata type or the other, and it worked. ...And then it didn't work, for some reason. - I was debugging this for 4 hours and couldn't figure it out. - So, raw-ass Lua funcs, here we go. THIS works. - Working with pointers gives me a headache. - */ - void *p = lua_touserdata(L, 1); - if (p != NULL) - { - if (lua_getmetatable(L, 1)) - { - CONS_Printf("case A\n"); - lua_getfield(L, LUA_REGISTRYINDEX, META_ITEMROULETTE); - if (lua_rawequal(L, -1, -2)) - { - CONS_Printf("case A2\n"); - *itemRoulette = *(itemroulette_t **)p; - } - else - { - CONS_Printf("case B\n"); - lua_pop(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, META_PLAYER); - if (lua_rawequal(L, -1, -2)) - { - CONS_Printf("case B2\n"); - *player = *(player_t **)p; - *itemRoulette = &(*player)->itemRoulette; - } - lua_pop(L, 2); - } - } - } -} - static int lib_kAddItemToReel(lua_State *L) { - player_t *player = NULL; + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); itemroulette_t *itemRoulette = NULL; - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); - NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; if (lua_isnumber(L, 2)) { @@ -4236,15 +4195,13 @@ static int lib_kAddItemToReel(lua_State *L) static int lib_kPushToRouletteItemList(lua_State *L) { - player_t *player = NULL; - itemroulette_t *itemRoulette = NULL; - - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); - + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + itemroulette_t *itemRoulette = NULL; NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; if (lua_isnumber(L, 2)) { @@ -4346,16 +4303,16 @@ static int lib_kGetItemRouletteDistance(lua_State *L) static int lib_kFillItemRouletteData(lua_State *L) { - player_t *player = NULL; + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); itemroulette_t *itemRoulette = NULL; - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); boolean ringbox = lua_optboolean(L, 2); NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; K_FillItemRouletteData(player, itemRoulette, ringbox, false); return 0; @@ -4439,15 +4396,14 @@ static int lib_kItemOddsScale(lua_State *L) static int lib_kWipeItemsInReel(lua_State *L) { - player_t *player = NULL; + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); itemroulette_t *itemRoulette = NULL; - - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); - + NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; itemRoulette->itemList.len = 0; return 0; @@ -4455,17 +4411,17 @@ static int lib_kWipeItemsInReel(lua_State *L) static int lib_kSetItemInReelByIndex(lua_State *L) { - player_t *player = NULL; + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); itemroulette_t *itemRoulette = NULL; - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); size_t index = luaL_checkinteger(L, 2) - 1; kartitems_t item = luaL_checkinteger(L, 3); NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; if (itemRoulette->itemList.len == 0) return luaL_error(L, "There are no items in the roulette to set."); @@ -4487,18 +4443,18 @@ static void AddOrPushToItemReel(player_t *player, itemroulette_t *roulette, kart static int lib_kAddItemToReelByIndex(lua_State *L) { - player_t *player = NULL; + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); itemroulette_t *itemRoulette = NULL; - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); size_t index = luaL_checkinteger(L, 2) - 1; kartitems_t item = luaL_checkinteger(L, 3); boolean addRings = lua_optboolean(L, 4); NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; // If the list is empty, just add the item silently and leave. if (itemRoulette->itemList.len == 0) { @@ -4539,16 +4495,16 @@ static int lib_kAddItemToReelByIndex(lua_State *L) static int lib_kRemoveItemFromReelByIndex(lua_State *L) { - player_t *player = NULL; + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); itemroulette_t *itemRoulette = NULL; - getItemRouletteOrPlayerBasedOnFirstParam(L, &player, &itemRoulette); size_t index = luaL_checkinteger(L, 2) - 1; NOHUD INLEVEL - if (!player && !itemRoulette) - return LUA_ErrInvalid(L, "player_t/itemroulette_t"); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + itemRoulette = &player->itemRoulette; if (itemRoulette->itemList.len == 0) return luaL_error(L, "There are no items in the roulette to delete."); From 23912a7c63901480fc568e3bd7df7b03d404852a Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 10 Jul 2025 04:48:19 -0400 Subject: [PATCH 30/46] Init roulette before prehook can bail, IDIOT --- src/k_roulette.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index b76ee6bae..c2748eb29 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1164,18 +1164,39 @@ static boolean K_TimingPermitsItem(kartitems_t item, const itemroulette_t *roule void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, boolean ringbox) { + K_InitRoulette(roulette); + + if (player != NULL) + { + roulette->baseDist = K_UndoMapScaling(player->distancetofinish); + + if (player->pflags & PF_AUTOROULETTE) + roulette->autoroulette = true; + + K_CalculateRouletteSpeed(roulette); + } + + CONS_Printf("HC: prehook\n"); // Lua may want to intercept reelbuilder entirely. LUA_HookPreFillItemRoulette(player, roulette); + + CONS_Printf("HC: bail\n"); // If prehook did something, no need to continue. if (roulette->itemList.len != 0) { return; } + CONS_Printf("HC: fill\n"); + K_FillItemRouletteData(player, roulette, ringbox, false); + CONS_Printf("HC: posthook\n"); + // Lua can modify the final result. LUA_HookFillItemRoulette(player, roulette); + + CONS_Printf("HC: out\n"); // If somehow there's no items, add sad. if (roulette->itemList.len == 0) { @@ -1198,18 +1219,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo kartitems_t singleItem = KITEM_SAD; size_t i, j; - - K_InitRoulette(roulette); - - if (player != NULL) - { - roulette->baseDist = K_UndoMapScaling(player->distancetofinish); - - if (player->pflags & PF_AUTOROULETTE) - roulette->autoroulette = true; - - K_CalculateRouletteSpeed(roulette); - } if (ringbox == true) { From 4217c9e214bdcf8611df93adbc096530ce3819a2 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 10 Jul 2025 04:51:41 -0400 Subject: [PATCH 31/46] No need to pass a roulette to lua itemresult --- src/lua_baselib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index edb5fe556..c49e5e8ee 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3943,9 +3943,8 @@ static int lib_kItemResultToType(lua_State *L) static int lib_kItemResultToAmount(lua_State *L) { kartitems_t item = luaL_checkinteger(L, 1); - itemroulette_t *roulette = *((itemroulette_t **)luaL_checkudata(L, 2, META_ITEMROULETTE)); //HUDSAFE - lua_pushinteger(L, K_ItemResultToAmount(item, roulette)); + lua_pushinteger(L, K_ItemResultToAmount(item, NULL)); return 1; } From 5c0a03f696389ccc6c83ed842b185b9d5ef31ab4 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 10 Jul 2025 17:21:41 -0400 Subject: [PATCH 32/46] Fix debugitemodds allocations, add extra prints --- src/k_roulette.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/k_roulette.c b/src/k_roulette.c index c2748eb29..945161147 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -734,6 +734,8 @@ static void K_InitRoulette(itemroulette_t *const roulette) { size_t i; + CONS_Printf("HC: init\n"); + #ifndef ITEM_LIST_SIZE if (roulette->itemList.items == NULL) { @@ -744,6 +746,8 @@ static void K_InitRoulette(itemroulette_t *const roulette) NULL ); + CONS_Printf("HC: alloc init\n"); + if (roulette->itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); @@ -847,6 +851,8 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) NULL ); + CONS_Printf("HC: alloc double to %d\n", roulette->itemList.cap); + if (roulette->itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); @@ -856,6 +862,8 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) roulette->itemList.items[ roulette->itemList.len ] = item; roulette->itemList.len++; + + CONS_Printf("HC: adding item %d - %d\n", item, roulette->itemList.len); } /*-------------------------------------------------- @@ -1219,6 +1227,11 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo kartitems_t singleItem = KITEM_SAD; size_t i, j; + + if (roulette->itemList.items == NULL) + { + K_InitRoulette(roulette); + } if (ringbox == true) { From 5ce7cf0a998ce9044cc403ee86b4787c37e97818 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 16 Jul 2025 05:35:51 -0400 Subject: [PATCH 33/46] Fix Lua roulette hooks not knowing what the fuck a ringbox is --- src/k_roulette.c | 18 ++++++++++++++++-- src/lua_hook.h | 4 ++-- src/lua_hooklib.c | 8 ++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 945161147..52d42d5dd 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -841,6 +841,20 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) #else I_Assert(roulette->itemList.items != NULL); + CONS_Printf("HC: trying push %d\n", item); + + if (!roulette->ringbox && item >= NUMKARTRESULTS) + { + CONS_Alert(CONS_WARNING, M_GetText("Item Roulette rejected an out-of-range item.\n")); + return; + } + + if (roulette->ringbox && item >= KSM__MAX) + { + CONS_Alert(CONS_WARNING, M_GetText("Casino Roulette rejected an out-of-range item.\n")); + return; + } + if (roulette->itemList.len >= roulette->itemList.cap) { roulette->itemList.cap *= 2; @@ -1186,7 +1200,7 @@ void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, CONS_Printf("HC: prehook\n"); // Lua may want to intercept reelbuilder entirely. - LUA_HookPreFillItemRoulette(player, roulette); + LUA_HookPreFillItemRoulette(player, roulette, ringbox); CONS_Printf("HC: bail\n"); @@ -1202,7 +1216,7 @@ void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, CONS_Printf("HC: posthook\n"); // Lua can modify the final result. - LUA_HookFillItemRoulette(player, roulette); + LUA_HookFillItemRoulette(player, roulette, ringbox); CONS_Printf("HC: out\n"); diff --git a/src/lua_hook.h b/src/lua_hook.h index 8187cbaa7..d44423400 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -148,8 +148,8 @@ void LUA_HookPlayerQuit(player_t *, kickreason_t); //int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend); -int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette); -int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette); +int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); +int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox); #ifdef __cplusplus } // extern "C" diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 0d9b72cbe..45805a062 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1034,15 +1034,15 @@ static int roulette_hook( return hook.status; } -int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette) +int LUA_HookPreFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox) { - return roulette_hook(player, roulette, false, HOOK(PreFillItemRoulette), res_true); + return roulette_hook(player, roulette, ringbox, HOOK(PreFillItemRoulette), res_true); } -int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette) +int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox) { - return roulette_hook(player, roulette, false, HOOK(FillItemRoulette), res_true); + return roulette_hook(player, roulette, ringbox, HOOK(FillItemRoulette), res_true); } boolean hook_cmd_running = false; From ccc9211617daa713a453d88383e1a135c894d541 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 16 Jul 2025 06:10:50 -0400 Subject: [PATCH 34/46] Don't put KITEM_SAD into Casino Roulette, idiot! --- src/k_roulette.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 52d42d5dd..a09d58c3b 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1222,7 +1222,10 @@ void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, // If somehow there's no items, add sad. if (roulette->itemList.len == 0) { - K_AddItemToReel(player, roulette, KITEM_SAD); + if (roulette->ringbox) + K_PushToRouletteItemList(roulette, KSM_BAR); + else + K_AddItemToReel(player, roulette, KITEM_SAD); } } From 530de8814339a4cb79f79889e85fab57d10b3162 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 20:18:03 -0400 Subject: [PATCH 35/46] Whoops --- src/k_roulette.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index a09d58c3b..c58cfbbfe 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -96,14 +96,15 @@ static UINT32 K_DynamicItemOddsRace[NUMKARTRESULTS-1][2] = {1, 1}, // lightningshield {25, 4}, // bubbleshield {66, 9}, // flameshield - {1, 3}, // hyudoro + {1, 2}, // hyudoro {0, 0}, // pogospring {30, 8}, // superring (SPECIAL! distance value specifies when this can NO LONGER appear) {0, 0}, // kitchensink - {1, 3}, // droptarget + {1, 2}, // droptarget {43, 5}, // gardentop {0, 0}, // gachabom - {1, 3}, // stoneshoe + {1, 2}, // stoneshoe + {1, 2}, // toxomister {45, 6}, // dualsneaker {55, 8}, // triplesneaker {25, 2}, // triplebanana @@ -140,6 +141,7 @@ static UINT32 K_DynamicItemOddsBattle[NUMKARTRESULTS-1][2] = {0, 0}, // gardentop {10, 5}, // gachabom {0, 0}, // stoneshoe + {0, 0}, // toxomister {0, 0}, // dualsneaker {20, 1}, // triplesneaker {0, 0}, // triplebanana @@ -176,6 +178,7 @@ static UINT32 K_DynamicItemOddsSpecial[NUMKARTRESULTS-1][2] = {0, 0}, // gardentop {0, 0}, // gachabom {0, 0}, // stoneshoe + {0, 0}, // toxomister {35, 2}, // dualsneaker {0, 0}, // triplesneaker {0, 0}, // triplebanana @@ -212,6 +215,7 @@ static UINT8 K_KartLegacyBattleOdds[NUMKARTRESULTS-1][2] = { 0, 0 }, // Garden Top { 5, 0 }, // Gachabom { 0, 1 }, // Stone Shoe + { 0, 1 }, // Toxomister { 0, 0 }, // Sneaker x2 { 0, 1 }, // Sneaker x3 { 0, 0 }, // Banana x3 @@ -373,6 +377,7 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result) case KITEM_EGGMAN: case KITEM_GACHABOM: case KITEM_STONESHOE: + case KITEM_TOXOMISTER: case KITEM_KITCHENSINK: { // Used when in 1st place and relatively far from players. @@ -887,6 +892,9 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) --------------------------------------------------*/ void K_AddItemToReel(const player_t *player, itemroulette_t *const roulette, kartitems_t item) { + if (player && K_PlayerUsesBotMovement(player) && !K_BotUnderstandsItem(item)) + return; + K_PushToRouletteItemList(roulette, item); if (player == NULL) @@ -1007,6 +1015,7 @@ static boolean K_IsItemFirstOnly(kartitems_t item) case KITEM_HYUDORO: case KITEM_DROPTARGET: case KITEM_STONESHOE: + case KITEM_TOXOMISTER: return true; default: return false; @@ -1184,6 +1193,22 @@ static boolean K_TimingPermitsItem(kartitems_t item, const itemroulette_t *roule return true; } +static void K_FixEmptyRoulette(const player_t *player, itemroulette_t *const roulette) +{ + if (roulette->itemList.len > 0) + return; + + if (K_PlayerUsesBotMovement(player)) // Bots can't use certain items. Give them _something_. + K_PushToRouletteItemList(roulette, KITEM_SUPERRING); + else // Players can use all items, so this should never happen. + K_PushToRouletteItemList(roulette, KITEM_SAD); +} + +/*-------------------------------------------------- + void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox) + + See header file for description. +--------------------------------------------------*/ void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, boolean ringbox) { K_InitRoulette(roulette); @@ -1367,6 +1392,7 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo if (K_ForcedSPB(player, roulette) == true) { K_AddItemToReel(player, roulette, KITEM_SPB); + K_FixEmptyRoulette(player, roulette); return; } @@ -1391,6 +1417,7 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo // singleItem = KITEM_SAD by default, // so it will be used when all items are turned off. K_AddItemToReel(player, roulette, singleItem); + K_FixEmptyRoulette(player, roulette); return; } @@ -1746,6 +1773,8 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo totalSpawnChance--; } + + K_FixEmptyRoulette(player, roulette); } /*-------------------------------------------------- From 4049b06b4c946f786fc3f164e482e0ada5edafad Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 20:20:24 -0400 Subject: [PATCH 36/46] Remove debug prints --- src/k_roulette.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index c58cfbbfe..d36c9ca2d 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -739,8 +739,6 @@ static void K_InitRoulette(itemroulette_t *const roulette) { size_t i; - CONS_Printf("HC: init\n"); - #ifndef ITEM_LIST_SIZE if (roulette->itemList.items == NULL) { @@ -751,8 +749,6 @@ static void K_InitRoulette(itemroulette_t *const roulette) NULL ); - CONS_Printf("HC: alloc init\n"); - if (roulette->itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); @@ -846,8 +842,6 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) #else I_Assert(roulette->itemList.items != NULL); - CONS_Printf("HC: trying push %d\n", item); - if (!roulette->ringbox && item >= NUMKARTRESULTS) { CONS_Alert(CONS_WARNING, M_GetText("Item Roulette rejected an out-of-range item.\n")); @@ -870,8 +864,6 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) NULL ); - CONS_Printf("HC: alloc double to %d\n", roulette->itemList.cap); - if (roulette->itemList.items == NULL) { I_Error("Not enough memory for item roulette list\n"); @@ -881,8 +873,6 @@ void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) roulette->itemList.items[ roulette->itemList.len ] = item; roulette->itemList.len++; - - CONS_Printf("HC: adding item %d - %d\n", item, roulette->itemList.len); } /*-------------------------------------------------- @@ -1223,27 +1213,18 @@ void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, K_CalculateRouletteSpeed(roulette); } - CONS_Printf("HC: prehook\n"); // Lua may want to intercept reelbuilder entirely. LUA_HookPreFillItemRoulette(player, roulette, ringbox); - - CONS_Printf("HC: bail\n"); // If prehook did something, no need to continue. if (roulette->itemList.len != 0) { return; } - CONS_Printf("HC: fill\n"); - K_FillItemRouletteData(player, roulette, ringbox, false); - CONS_Printf("HC: posthook\n"); - // Lua can modify the final result. LUA_HookFillItemRoulette(player, roulette, ringbox); - - CONS_Printf("HC: out\n"); // If somehow there's no items, add sad. if (roulette->itemList.len == 0) { From 76b88990ccc6c110b545c777d8ba83393347788a Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 31 Jul 2025 06:12:20 -0400 Subject: [PATCH 37/46] WIP: Foes --- src/d_player.h | 1 + src/g_game.c | 3 + src/k_bot.cpp | 4 +- src/k_botitem.cpp | 2 +- src/k_grandprix.cpp | 168 ++++++++++++++++++++++++++++++-------------- src/k_hud.cpp | 2 +- src/k_kart.c | 18 +++++ src/p_saveg.cpp | 4 ++ src/p_saveg.h | 1 + 9 files changed, 148 insertions(+), 55 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e73ff2e12..03527a1ae 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -418,6 +418,7 @@ struct botvars_t UINT8 difficulty; // Bot's difficulty setting INT16 diffincrease; // In GP: bot difficulty will increase this much next round boolean rival; // If true, they're the GP rival + boolean foe; // If true, in contention for top X // All entries above persist between rounds and must be recorded in demos diff --git a/src/g_game.c b/src/g_game.c index e59199a08..1b5b5208f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2271,6 +2271,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT16 botdiffincrease; boolean botrival; + boolean botfoe; boolean cangrabitems; @@ -2381,6 +2382,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) botdiffincrease = players[player].botvars.diffincrease; botrival = players[player].botvars.rival; + botfoe = players[player].botvars.foe; totalring = players[player].totalring; xtralife = players[player].xtralife; @@ -2641,6 +2643,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->spheres = spheres; p->botvars.diffincrease = botdiffincrease; p->botvars.rival = botrival; + p->botvars.foe = botfoe; p->xtralife = xtralife; // SRB2kart diff --git a/src/k_bot.cpp b/src/k_bot.cpp index bb4cb3e5c..26ea3a022 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -620,7 +620,7 @@ static UINT32 K_BotRubberbandDistance(const player_t *player) UINT8 pos = 1; UINT8 i; - if (player->botvars.rival || cv_levelskull.value) + if (player->botvars.rival || player->botvars.foe || cv_levelskull.value) { // The rival should always try to be the front runner for the race. return 0; @@ -694,6 +694,8 @@ fixed_t K_BotRubberband(const player_t *player) { UINT8 levelreduce = std::min(3, player->botvars.difficulty/4); // How much to drop the "effective level" of bots that are consistently behind expreduce = Easing_Linear((K_EffectiveGradingFactor(player) - MINGRADINGFACTOR) * 2, levelreduce*FRACUNIT, 0); + if (player->botvars.foe) + expreduce /= 2; } fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1); diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index d042f0faa..46a6748a4 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -299,7 +299,7 @@ static boolean K_RivalBotAggression(const player_t *bot, const player_t *target) return false; } - if (bot->botvars.rival == false && !cv_levelskull.value) + if (!(bot->botvars.rival || bot->botvars.foe) && !cv_levelskull.value) { // Not the rival, we aren't self-aware. return false; diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index d990dd94a..06ff42578 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -98,6 +98,117 @@ static UINT8 K_GetOffsetStartingDifficulty(const UINT8 startingdifficulty, UINT8 return startingdifficulty - offset; } +/*-------------------------------------------------- + static INT16 K_RivalScore(player_t *bot) + + Creates a "rival score" for a bot, used to determine which bot is the + most deserving of the rival status. + + Input Arguments:- + bot - Player to check. + + Return:- + "Rival score" value. +--------------------------------------------------*/ +static INT16 K_RivalScore(player_t *bot) +{ + const UINT16 difficulty = bot->botvars.difficulty; + const UINT16 score = bot->score; + SINT8 roundnum = 1, roundsleft = 1; + UINT16 lowestscore = UINT16_MAX; + UINT8 lowestdifficulty = MAXBOTDIFFICULTY; + UINT8 i; + + if (grandprixinfo.cup != NULL && roundqueue.size > 0) + { + roundnum = roundqueue.roundnum; + roundsleft = grandprixinfo.cup->numlevels - roundnum; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + if (players[i].score < lowestscore) + { + lowestscore = players[i].score; + } + + if (players[i].bot == true && players[i].botvars.difficulty < lowestdifficulty) + { + lowestdifficulty = players[i].botvars.difficulty; + } + } + + // In the early game, difficulty is more important. + // This will try to influence the higher difficulty bots to get rival more often & get even more points. + // However, when we're running low on matches left, we need to focus more on raw score! + + return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * roundnum); +} + +static boolean CompareRivals(player_t *a, player_t *b) +{ + CONS_Printf("compare foes\n"); + if (a == NULL) + return false; + if (b == NULL) + return true; + + CONS_Printf("%s %d VS %s %d\n", player_names[a-players], K_RivalScore(a), player_names[b-players], K_RivalScore(b)); + + if (K_RivalScore(a) != K_RivalScore(b)) + { + // Push bad position to the back. + CONS_Printf("returning known\n"); + return (K_RivalScore(a) > K_RivalScore(b)); + } + + CONS_Printf("returning shuffle\n"); + + // They are equals, so just randomize + return (P_Random(PR_BOTS) & 1); +} + +static void K_AssignFoes(void) +{ + std::vector bots; + CONS_Printf("foe assignment\n"); + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] == false) + continue; + + player_t *player = &players[i]; + + if (!player->spectator && player->bot) + { + CONS_Printf("added %s\n", player_names[i]); + bots.push_back(player); + player->botvars.foe = false; + } + } + + CONS_Printf("sort foes\n"); + std::stable_sort(bots.begin(), bots.end(), CompareRivals); + + UINT8 i = 0; + for (auto &bot : bots) + { + CONS_Printf("assign foes\n"); + + if (bot != NULL) + bot->botvars.foe = true; + + i++; + if (i > 2) + break; + } +} + /*-------------------------------------------------- void K_InitGrandPrixBots(void) @@ -254,6 +365,8 @@ void K_InitGrandPrixBots(void) { break; } + if (i <= 2) + players[newplayernum-1].botvars.foe = true; } } @@ -289,64 +402,13 @@ void K_LoadGrandPrixSaveGame(void) K_SetBot(i, savedata.bots[i].skin, savedata.bots[i].difficulty, BOT_STYLE_NORMAL); players[i].botvars.rival = savedata.bots[i].rival; + players[i].botvars.foe = savedata.bots[i].foe; players[i].score = savedata.bots[i].score; players[i].spectator = K_BotDefaultSpectator(); } } -/*-------------------------------------------------- - static INT16 K_RivalScore(player_t *bot) - - Creates a "rival score" for a bot, used to determine which bot is the - most deserving of the rival status. - - Input Arguments:- - bot - Player to check. - - Return:- - "Rival score" value. ---------------------------------------------------*/ -static INT16 K_RivalScore(player_t *bot) -{ - const UINT16 difficulty = bot->botvars.difficulty; - const UINT16 score = bot->score; - SINT8 roundnum = 1, roundsleft = 1; - UINT16 lowestscore = UINT16_MAX; - UINT8 lowestdifficulty = MAXBOTDIFFICULTY; - UINT8 i; - - if (grandprixinfo.cup != NULL && roundqueue.size > 0) - { - roundnum = roundqueue.roundnum; - roundsleft = grandprixinfo.cup->numlevels - roundnum; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - { - continue; - } - - if (players[i].score < lowestscore) - { - lowestscore = players[i].score; - } - - if (players[i].bot == true && players[i].botvars.difficulty < lowestdifficulty) - { - lowestdifficulty = players[i].botvars.difficulty; - } - } - - // In the early game, difficulty is more important. - // This will try to influence the higher difficulty bots to get rival more often & get even more points. - // However, when we're running low on matches left, we need to focus more on raw score! - - return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * roundnum); -} - /*-------------------------------------------------- void K_UpdateGrandPrixBots(void) @@ -374,6 +436,8 @@ void K_UpdateGrandPrixBots(void) players[i].spectator = K_BotDefaultSpectator(); } + K_AssignFoes(); + if (grandprixinfo.wonround == false) { return; diff --git a/src/k_hud.cpp b/src/k_hud.cpp index c3e444930..9260996b1 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -7314,7 +7314,7 @@ static void K_DrawBotDebugger(void) V_DrawSmallString(8, 14, 0, va("Difficulty: %d / %d", bot->botvars.difficulty, MAXBOTDIFFICULTY)); V_DrawSmallString(8, 18, 0, va("Difficulty increase: %d", bot->botvars.diffincrease)); - V_DrawSmallString(8, 22, 0, va("Rival: %d", (UINT8)(bot->botvars.rival == true))); + V_DrawSmallString(8, 22, 0, va("Rival / Foe: %d / %d", (UINT8)(bot->botvars.rival == true), (UINT8)(bot->botvars.foe == true))); V_DrawSmallString(8, 26, 0, va("Rubberbanding: %.02f", FIXED_TO_FLOAT(bot->botvars.rubberband) * 100.0f)); V_DrawSmallString(8, 32, 0, va("Item delay: %d", bot->botvars.itemdelay)); diff --git a/src/k_kart.c b/src/k_kart.c index ce6d07536..a5c95eab5 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1621,6 +1621,8 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed // Double speed for the rival! if (player->botvars.rival || cv_levelskull.value) player->draftpower += add; + else if (player->botvars.foe) + player->draftpower += add/2; else if (dest->player->bot) // Reduce bot gluts. player->draftpower -= 3*add/4; } @@ -3554,6 +3556,10 @@ static fixed_t K_RingDurationBoost(const player_t *player) // x2.0 for Rival ret *= 2; } + else if (player->botvars.foe) + { + ret = 3 * ret / 2; + } } return ret; @@ -3976,6 +3982,11 @@ fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dor // +10% top speed for the rival finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10); } + else if (player->bot && player->botvars.foe) + { + // +5% for foes + finalspeed = FixedMul(finalspeed, 21*FRACUNIT/20); + } } } @@ -10965,6 +10976,13 @@ void K_KartResetPlayerColor(player_t *player) goto base; } + if (player->botvars.foe) + { + player->mo->colorized = true; + player->mo->color = SKINCOLOR_BLACK; + goto finalise; + } + if (player->eggmanexplode) // You're gonna diiiiie { const INT32 flashtime = 4<<(player->eggmanexplode/TICRATE); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 45da46e47..0d57458d0 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -138,6 +138,7 @@ static inline void P_ArchivePlayer(savebuffer_t *save) WRITEUINT8(save->p, players[i].botvars.difficulty); WRITEUINT8(save->p, (UINT8)players[i].botvars.rival); + WRITEUINT8(save->p, (UINT8)players[i].botvars.foe); WRITEUINT32(save->p, players[i].score); } @@ -195,6 +196,7 @@ static boolean P_UnArchivePlayer(savebuffer_t *save) savedata.bots[pid].difficulty = READUINT8(save->p); savedata.bots[pid].rival = (boolean)READUINT8(save->p); + savedata.bots[pid].foe = (boolean)READUINT8(save->p); savedata.bots[pid].score = READUINT32(save->p); } @@ -765,6 +767,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].botvars.difficulty); WRITEUINT8(save->p, players[i].botvars.diffincrease); WRITEUINT8(save->p, players[i].botvars.rival); + WRITEUINT8(save->p, players[i].botvars.foe); WRITEFIXED(save->p, players[i].botvars.rubberband); WRITEUINT8(save->p, players[i].botvars.bumpslow); WRITEUINT32(save->p, players[i].botvars.itemdelay); @@ -1430,6 +1433,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].botvars.difficulty = READUINT8(save->p); players[i].botvars.diffincrease = READUINT8(save->p); players[i].botvars.rival = (boolean)READUINT8(save->p); + players[i].botvars.foe = (boolean)READUINT8(save->p); players[i].botvars.rubberband = READFIXED(save->p); players[i].botvars.bumpslow = READUINT8(save->p); players[i].botvars.itemdelay = READUINT32(save->p); diff --git a/src/p_saveg.h b/src/p_saveg.h index f0beb35e3..1848550ad 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -46,6 +46,7 @@ struct savedata_bot_s UINT8 skin; UINT8 difficulty; boolean rival; + boolean foe; UINT32 score; }; From bb417816c2434d35969f0c0b51b7cb208a7b35c1 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 31 Jul 2025 15:22:03 -0400 Subject: [PATCH 38/46] Foes use tighter rubberbanding target --- src/k_bot.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 26ea3a022..02cdbb8e5 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -615,17 +615,20 @@ fixed_t K_BotMapModifier(void) --------------------------------------------------*/ static UINT32 K_BotRubberbandDistance(const player_t *player) { - const UINT32 spacing = FixedDiv(640 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT; + UINT32 spacing = FixedDiv(640 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT; const UINT8 portpriority = player - players; UINT8 pos = 1; UINT8 i; - if (player->botvars.rival || player->botvars.foe || cv_levelskull.value) + if (player->botvars.rival || cv_levelskull.value) { // The rival should always try to be the front runner for the race. return 0; } + if (player->botvars.foe) + spacing /= 2; + for (i = 0; i < MAXPLAYERS; i++) { if (i == portpriority) From ec36f6bb01f7995bf6c96e88726410389a5b5356 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 1 Aug 2025 15:31:14 -0400 Subject: [PATCH 39/46] Guarantee that Foes/Rivals always try to pass generic bots --- src/k_bot.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 02cdbb8e5..aa3252ece 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -652,6 +652,11 @@ static UINT32 K_BotRubberbandDistance(const player_t *player) continue; } + if (player->botvars.foe && !players[i].botvars.foe) + { + continue; + } + // First check difficulty levels, then score, then settle it with port priority! if (player->botvars.difficulty < players[i].botvars.difficulty) { From 528eaf0e64fbc3bc55e60374394f506819228fd7 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 3 Aug 2025 18:10:05 -0400 Subject: [PATCH 40/46] I would really like to believe that this just makes foes work in demos --- src/g_demo.cpp | 4 ++++ src/k_grandprix.cpp | 11 ----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 172309016..17e095e29 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -321,6 +321,7 @@ void G_ReadDemoExtraData(void) players[p].botvars.difficulty = READUINT8(demobuf.p); players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic players[p].botvars.rival = (boolean)READUINT8(demobuf.p); + players[p].botvars.foe = (boolean)READUINT8(demobuf.p); } } if (extradata & DXD_PLAYSTATE) @@ -497,6 +498,7 @@ void G_WriteDemoExtraData(void) WRITEUINT8(demobuf.p, players[i].botvars.difficulty); WRITEINT16(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.rival); + WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.foe); } } if (demo_extradata[i] & DXD_PLAYSTATE) @@ -2111,6 +2113,7 @@ void G_BeginRecording(void) WRITEUINT8(demobuf.p, player->botvars.difficulty); WRITEINT16(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic WRITEUINT8(demobuf.p, (UINT8)player->botvars.rival); + WRITEUINT8(demobuf.p, (UINT8)player->botvars.foe); } // Name @@ -3222,6 +3225,7 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum) players[p].botvars.difficulty = READUINT8(demobuf.p); players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic players[p].botvars.rival = (boolean)READUINT8(demobuf.p); + players[p].botvars.foe = (boolean)READUINT8(demobuf.p); } K_UpdateShrinkCheat(&players[p]); diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 06ff42578..6b6610ff9 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -152,23 +152,17 @@ static INT16 K_RivalScore(player_t *bot) static boolean CompareRivals(player_t *a, player_t *b) { - CONS_Printf("compare foes\n"); if (a == NULL) return false; if (b == NULL) return true; - CONS_Printf("%s %d VS %s %d\n", player_names[a-players], K_RivalScore(a), player_names[b-players], K_RivalScore(b)); - if (K_RivalScore(a) != K_RivalScore(b)) { // Push bad position to the back. - CONS_Printf("returning known\n"); return (K_RivalScore(a) > K_RivalScore(b)); } - CONS_Printf("returning shuffle\n"); - // They are equals, so just randomize return (P_Random(PR_BOTS) & 1); } @@ -176,7 +170,6 @@ static boolean CompareRivals(player_t *a, player_t *b) static void K_AssignFoes(void) { std::vector bots; - CONS_Printf("foe assignment\n"); for (UINT8 i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] == false) @@ -186,20 +179,16 @@ static void K_AssignFoes(void) if (!player->spectator && player->bot) { - CONS_Printf("added %s\n", player_names[i]); bots.push_back(player); player->botvars.foe = false; } } - CONS_Printf("sort foes\n"); std::stable_sort(bots.begin(), bots.end(), CompareRivals); UINT8 i = 0; for (auto &bot : bots) { - CONS_Printf("assign foes\n"); - if (bot != NULL) bot->botvars.foe = true; From 73438dd629c9fb722b58da73d99ab8947b0fe227 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 3 Aug 2025 18:17:30 -0400 Subject: [PATCH 41/46] Subdued foes --- src/k_bot.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index aa3252ece..be95aaf81 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -626,8 +626,10 @@ static UINT32 K_BotRubberbandDistance(const player_t *player) return 0; } + /* if (player->botvars.foe) spacing /= 2; + */ for (i = 0; i < MAXPLAYERS; i++) { From 6a2568e7a7dd9b7442c1dd7f305641f1d007bcb2 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 3 Aug 2025 21:18:40 -0400 Subject: [PATCH 42/46] Foes in Match Race --- src/k_bot.cpp | 2 ++ src/k_grandprix.cpp | 4 ++-- src/k_grandprix.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index be95aaf81..251f0f3c8 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -408,6 +408,8 @@ void K_UpdateMatchRaceBots(void) clear_bots(wantedbots); } + K_AssignFoes(); + // We should have enough bots now :) #ifdef HAVE_DISCORDRPC diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 6b6610ff9..5196aac60 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -159,7 +159,7 @@ static boolean CompareRivals(player_t *a, player_t *b) if (K_RivalScore(a) != K_RivalScore(b)) { - // Push bad position to the back. + // Rival Score is HIGH when bots are strong. Sort them first! return (K_RivalScore(a) > K_RivalScore(b)); } @@ -167,7 +167,7 @@ static boolean CompareRivals(player_t *a, player_t *b) return (P_Random(PR_BOTS) & 1); } -static void K_AssignFoes(void) +void K_AssignFoes(void) { std::vector bots; for (UINT8 i = 0; i < MAXPLAYERS; i++) diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 8b62187dc..b3e1620bd 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -200,6 +200,8 @@ boolean K_CanChangeRules(boolean allowdemos); boolean K_BotDefaultSpectator(void); +void K_AssignFoes(void); + #ifdef __cplusplus } // extern "C" From d78afd9de38fb3cd1a26db21a7236c4f1ae14604 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 3 Aug 2025 23:36:38 -0400 Subject: [PATCH 43/46] Red FOE nametags, try not to sort empty lists of bots --- src/k_grandprix.cpp | 15 ++++++--- src/k_hud.cpp | 38 +++++++++++----------- src/k_kart.c | 77 +++++++++++++++++++++------------------------ 3 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 5196aac60..8c88de5fa 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -170,6 +170,8 @@ static boolean CompareRivals(player_t *a, player_t *b) void K_AssignFoes(void) { std::vector bots; + boolean addedplayer = false; + for (UINT8 i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] == false) @@ -179,16 +181,21 @@ void K_AssignFoes(void) if (!player->spectator && player->bot) { + addedplayer = true; bots.push_back(player); player->botvars.foe = false; } } + // Why the fuck is this blowing up sometimes + if (!addedplayer) + return; + std::stable_sort(bots.begin(), bots.end(), CompareRivals); UINT8 i = 0; for (auto &bot : bots) - { + { if (bot != NULL) bot->botvars.foe = true; @@ -425,13 +432,13 @@ void K_UpdateGrandPrixBots(void) players[i].spectator = K_BotDefaultSpectator(); } - K_AssignFoes(); - if (grandprixinfo.wonround == false) { return; } + K_AssignFoes(); + // Find the rival. for (i = 0; i < MAXPLAYERS; i++) { @@ -692,7 +699,7 @@ void K_IncreaseBotDifficulty(player_t *bot) // RELAXED MODE: // Continues don't drop bot difficulty, because we always advance. // Bots will still level up from standard advancement; we need a - // much steeper rank nudge to keep difficulty at the right level. + // much steeper rank nudge to keep difficulty at the right level. if (grandprixinfo.gamespeed == KARTSPEED_EASY) { switch(averageRank) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 9260996b1..60e32eed0 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -525,7 +525,7 @@ void K_LoadKartHUDGraphics(void) buffer[7] = '0'+((i) % 10); HU_UpdatePatch(&kp_overdrive[0][i], "%s", buffer); } - + sprintf(buffer, "bsOVRDxx"); for (i = 0; i < 32; i++) { @@ -2000,7 +2000,7 @@ static void K_drawKartItem(void) static void K_drawBackupItem(void) { bool tiny = r_splitscreen > 1; - patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw }; + patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw }; patch_t *localbg = (kp_itembg[2]); patch_t *localinv = kp_invincibility[((leveltime % (6*3)) / 3) + 7 + tiny]; INT32 fx = 0, fy = 0, fflags = 0, tx = 0, ty = 0; // final coords for hud and flags... @@ -3406,7 +3406,7 @@ static void K_drawKartDuelScores(void) { flags |= V_SNAPTOBOTTOM; flags &= ~V_SNAPTOTOP; - basey = BASEVIDHEIGHT - 40; + basey = BASEVIDHEIGHT - 40; } basex = BASEVIDWIDTH - 80; } @@ -3493,7 +3493,7 @@ static void K_drawKartDuelScores(void) V_DrawScaledPatch(basex-barheight+foeheight, basey, flags, kp_duel_4over); else V_DrawScaledPatch(basex, basey-barheight+foeheight, flags, kp_duel_over); - + if (!use4p) { V_DrawScaledPatch(basex, basey, flags, kp_duel_foe); @@ -3512,7 +3512,7 @@ static void K_drawKartDuelScores(void) } foenum.text("{}", foe->duelscore); - younum.text("{}", stplyr->duelscore); + younum.text("{}", stplyr->duelscore); // minirankings shamelessly copypasted because i know that shit works already // and SURELY we will never need to use this somewhere else, right? @@ -3526,7 +3526,7 @@ static void K_drawKartDuelScores(void) UINT8 drawme = draw ? (stplyr - players) : (foe - players); UINT16 drawx = basex + (draw ? youx : foex); UINT16 drawy = basey + (draw ? youy : foey); - + if (!playeringame[drawme] || players[drawme].spectator) continue; @@ -3790,8 +3790,8 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (R_GetViewNumber() == 1) { flags |= V_SNAPTOBOTTOM; - flags &= ~V_SNAPTOTOP; - basey = 170; + flags &= ~V_SNAPTOTOP; + basey = 170; } } } @@ -3817,7 +3817,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) return; using srb2::Draw; - srb2::Draw::Font scorefont = Draw::Font::kTimer; + srb2::Draw::Font scorefont = Draw::Font::kTimer; if (totalscore > 99) { @@ -3834,7 +3834,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) else { scorefont = Draw::Font::kZVote; - } + } } UINT32 youscore = stplyr->teamimportance; @@ -3870,7 +3870,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (teams_lastleveltime[vn] != leveltime) // Timing consistency { INT32 delta = abs(easedallyscore[vn] - allyscore); // how wrong is display score? - + if (scorechangecooldown[vn] == 0 && delta) { if (allyscore > easedallyscore[vn]) @@ -3886,9 +3886,9 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) enemycolor = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE); } scorechangecooldown[vn] = TICRATE/delta; - } + } } - + if (!fromintermission) { // replace scores with eased scores @@ -4009,7 +4009,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (totalscore > 99) { enemynum.text("{:03}", enemyscore); - allynum.text("{:03}", allyscore); + allynum.text("{:03}", allyscore); } else { @@ -5346,8 +5346,10 @@ static void K_DrawCPUTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flag K_DrawNameTagItemSpy(barx, bary, p, flags); } + UINT8 *foecol = R_GetTranslationColormap(TC_RAINBOW, static_cast(SKINCOLOR_RED), GTC_CACHE); + UINT8 blink = ((leveltime / 7) & 1); - V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_cpu[blink], NULL); + V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_cpu[blink], (p->botvars.foe) ? foecol : NULL); } static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flags) @@ -5856,13 +5858,13 @@ INT32 K_GetMinimapSplitFlags(const boolean usingProgressBar) #define ICON_DOT_RADIUS (10) // modified pick from blondedradio/RadioRacers (but there are like 57 things we don't want in the commit) -// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway) +// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway) static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags) { fixed_t amnumxpos, amnumypos; INT32 amxpos, amypos; - if (exitcountdown || leveltime > g_battleufo.due || battleprisons) + if (exitcountdown || leveltime > g_battleufo.due || battleprisons) return; tic_t raw = g_battleufo.due - leveltime; @@ -5872,7 +5874,7 @@ static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hud { flags |= (raw / (TICRATE/2) % 2) ? V_YELLOWMAP : 0; } - + if (countdown <= 10) { flags &= ~(V_HUDTRANS|V_HUDTRANSHALF); diff --git a/src/k_kart.c b/src/k_kart.c index a5c95eab5..620721f41 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -135,7 +135,7 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt) boolean K_InRaceDuel(void) { return ( - inDuel && + inDuel && (gametyperules & GTR_CIRCUIT) && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE) && !specialstageinfo.valid && @@ -3776,7 +3776,7 @@ static void K_GetKartBoostPower(player_t *player) // This one's a little special: we add extra top speed per tic of ringboost stored up, to allow for Ring Box to really rocket away. // (We compensate when decrementing ringboost to avoid runaway exponential scaling hell.) fixed_t rb = FixedDiv(player->ringboost * FRACUNIT, max(FRACUNIT, K_RingDurationBoost(player))); - fixed_t rp = ((9 - player->kartspeed) + (9 - player->kartweight)) * ((3*FRACUNIT/20)/16); + fixed_t rp = ((9 - player->kartspeed) + (9 - player->kartweight)) * ((3*FRACUNIT/20)/16); ADDBOOST( ringboost_base + FixedMul(FRACUNIT / 1750, rb) + rp, 4*FRACUNIT, @@ -3804,7 +3804,7 @@ static void K_GetKartBoostPower(player_t *player) // Even when not inputting a turn, drift prediction is hard. // Turn solver will sometimes need to slightly turn to stay "aligned". // Award full boost even if turn solver creates a fractional miniturn. - const INT16 inner_deadzone = KART_FULLTURN / 100; + const INT16 inner_deadzone = KART_FULLTURN / 100; INT16 steer_threshold = FixedMul((FRACUNIT * player->kartweight) / 9, max_steer_threshold)>>FRACBITS; @@ -4310,8 +4310,8 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact) UINT16 scaledamps = min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10); // Debug print for scaledamps calculation // CONS_Printf("K_SpawnAmps: player=%s, amps=%d, kartspeed=%d, kartweight=%d, itemdistance=%d, itemdistmult=%0.2f, statscaledamps=%d, distscaledamps=%d\n", - // player_names[player-players], amps, player->kartspeed, player->kartweight, - // itemdistance, FixedToFloat(itemdistmult), + // player_names[player-players], amps, player->kartspeed, player->kartweight, + // itemdistance, FixedToFloat(itemdistmult), // min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10), // FixedMul(scaledamps<>FRACBITS); scaledamps = FixedMul(scaledamps<>FRACBITS; @@ -4370,8 +4370,8 @@ void K_AwardPlayerAmps(player_t *player, UINT8 amps) if (oldamps/AMPLEVEL != player->amps/AMPLEVEL) { UINT8 amplevel = player->amps / AMPLEVEL; - static sfxenum_t bwips[7] = {sfx_mbs4c, - sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50, + static sfxenum_t bwips[7] = {sfx_mbs4c, + sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50, sfx_mbs51, sfx_mbs52}; amplevel = min(amplevel, 6); @@ -4435,7 +4435,7 @@ void K_CheckpointCrossAward(player_t *player) //CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp); if (!player->cangrabitems) player->cangrabitems = 1; - + K_AwardPlayerRings(player, (player->bot ? 20 : 10), true); // Update Duel scoring. @@ -6680,7 +6680,7 @@ void K_SpawnFireworkTrail(mobj_t *mo) if (mo->player) dust->color = mo->player->skincolor; - else + else dust->color = mo->color; dust->colorized = true; @@ -9366,7 +9366,7 @@ static void K_UpdateTripwire(player_t *player) else CONS_Printf("airtime: %d, twLen: %d, twAirLen: %d\n", player->airtime, player->tripwireLeniency, player->tripwireAirLeniency); */ - + if (boostExists) { // If player is MOSTLY on the ground. @@ -9557,13 +9557,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) for (doubler = 0; doubler < 2; doubler++) { fixed_t heightOffset = player->mo->height + (24*player->mo->scale); - if (P_IsObjectFlipped(player->mo)) + if (P_IsObjectFlipped(player->mo)) { // This counteracts the offset added by K_FlipFromObject so it looks seamless from non-flipped. heightOffset += player->mo->height - FixedMul(player->mo->scale, player->mo->height); heightOffset *= P_MobjFlip(player->mo); // Fleep. } - + mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, player->mo->z + P_GetMobjZMovement(player->mo) + heightOffset, MT_THOK); @@ -9675,7 +9675,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) sub = diff * (sub > 0 ? 1 : -1); player->mo->momz -= sub; } - + } else { @@ -10101,7 +10101,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->invincibilitytimer--; if (player->invincibilitytimer && K_PlayerScamPercentage(player, 1)) player->invincibilitytimer--; - + // Extra tripwire leniency for the end of invincibility if (player->invincibilitytimer <= 0) { player->tripwireLeniency = max( player->tripwireLeniency, TICRATE ); @@ -10112,7 +10112,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { // freeze the stunned timer while baildrop is active // while retaining the value that was initially set - player->stunned++; + player->stunned++; mobj_t *pmo = player->mo; // particle spawn @@ -10182,7 +10182,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->amps > 0) K_DefensiveOverdrive(player); - P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo); + P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo); player->bailhitlag = false; } @@ -10232,6 +10232,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } S_StartSound(player->mo, sfx_kc33); + P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo); + player->bailquake = false; } // The precise ordering of start-of-level made me want to cut my head off, @@ -10976,13 +10978,6 @@ void K_KartResetPlayerColor(player_t *player) goto base; } - if (player->botvars.foe) - { - player->mo->colorized = true; - player->mo->color = SKINCOLOR_BLACK; - goto finalise; - } - if (player->eggmanexplode) // You're gonna diiiiie { const INT32 flashtime = 4<<(player->eggmanexplode/TICRATE); @@ -13743,7 +13738,7 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) { INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT; INT16 SMALL_WAYPOINT = 450; - + if (myradius < SMALL_WAYPOINT) errorfrict *= 2; } @@ -14052,7 +14047,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // ...which nullifies a lot of designed advantages for accel types and high-weight racers. // // In addition, it's at Gear 3 Thunderdome speed, which can make it hard for heavies to - // take strong lines without brakedrifting. + // take strong lines without brakedrifting. // // To try and help close this gap, we fudge Ring Box payouts to allow weaker characters // better access to things that make them go fast, without changing core handling. @@ -14072,7 +14067,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // Scale from base payout at 9/1 to max payout at 1/9. award = Easing_InCubic(FRACUNIT*total/maxtotal, 13*award/10, 18*award/10); - // And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress! + // And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress! if (gametyperules & GTR_CIRCUIT) { UINT8 maxgrade = 10; @@ -14212,7 +14207,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (!(player->instaWhipCharge >= INSTAWHIP_CHARGETIME && P_PlayerInPain(player))) // Allow reversal whip player->instaWhipCharge = 0; } - + if (player->cmd.buttons & BT_BAIL && (player->cmd.buttons & BT_RESPAWNMASK) != BT_RESPAWNMASK) { if (leveltime < introtime || (gametyperules & GTR_SPHERES)) @@ -14846,7 +14841,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) mobj_t *at1 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL); mobj_t *at2 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL); mobj_t *at3 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL); - + P_SetMobjState(at1, S_THNG); P_SetMobjState(at2, S_THND); P_SetMobjState(at3, S_THNH); @@ -14857,7 +14852,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&at1->target, player->mo); P_SetTarget(&at2->target, player->mo); P_SetTarget(&at3->target, player->mo); - + S_StartSound(player->mo, LIGHTNING_SOUND); } break; @@ -14913,7 +14908,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->curshield != KSHIELD_BUBBLE) { mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BUBBLESHIELD); - // MT_BUBBLESHIELD doesn't have MF_NOBLOCKMAP so we need to remove this manually. + // MT_BUBBLESHIELD doesn't have MF_NOBLOCKMAP so we need to remove this manually. // Otherwise if you roll a bubble shield while flipped, the visuals look too mismatched. shield->eflags &= ~MFE_VERTICALFLIP; P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); @@ -15097,14 +15092,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { S_StartSound(player->mo, sfx_gsha7); - if (P_IsObjectOnGround(player->mo)) // facing angle blends w/ momentum angle for game-feel + if (P_IsObjectOnGround(player->mo)) // facing angle blends w/ momentum angle for game-feel { - P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale); - P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale); + P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale); + P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale); } else // air version is momentum angle only, reduces cheese, is twice as strong to compensate { - P_Thrust(player->mo, K_MomentumAngle(player->mo), 50*player->mo->scale); + P_Thrust(player->mo, K_MomentumAngle(player->mo), 50*player->mo->scale); } UINT8 numsparks = 8; @@ -16373,7 +16368,7 @@ boolean K_PlayerCanUseItem(player_t *player) return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime); } -// === +// === // THE EXP ZONE // === @@ -16387,7 +16382,7 @@ static boolean K_IsValidOpponent(player_t *me, player_t *them) return false; if (G_SameTeam(me, them)) return false; - + return true; } @@ -16479,7 +16474,7 @@ UINT16 K_GetEXP(player_t *player) UINT16 exp = FixedRescale(player->gradingfactor, factormin, factormax, Easing_Linear, targetminexp, targetmaxexp)>>FRACBITS; - // CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n", + // CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n", // player_names[player - players], numgradingpoints, player->gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp); return exp; @@ -16493,7 +16488,7 @@ UINT32 K_GetNumGradingPoints(void) return numlaps * (1 + Obj_GetCheckpointCount()); } -// === +// === // END EXP ZONE // === @@ -16512,7 +16507,7 @@ boolean K_IsPickMeUpItem(mobjtype_t type) extern consvar_t cv_debugpickmeup; if (cv_debugpickmeup.value) return false; - + switch (type) { case MT_JAWZ: @@ -16691,7 +16686,7 @@ boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2, boolean allowHostile) if (!K_PickUp(victim->player, inflictor)) return false; - K_AddHitLag(victim, 3, false); + K_AddHitLag(victim, 3, false); P_RemoveMobj(inflictor); return true; @@ -16718,7 +16713,7 @@ fixed_t K_TeamComebackMultiplier(player_t *player) else theirdistance += K_GetItemRouletteDistance(&players[i], players[i].itemRoulette.playing); } - + fixed_t multiplier = FixedDiv(ourdistance, theirdistance); multiplier = min(multiplier, 3*FRACUNIT); multiplier = max(multiplier, FRACUNIT); From 11f63ce79e2a9129806f34201df00d7156725300 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 4 Aug 2025 04:36:21 -0400 Subject: [PATCH 44/46] Rebase fixup --- src/k_kart.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 620721f41..eb251144f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10232,8 +10232,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } S_StartSound(player->mo, sfx_kc33); - P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo); - player->bailquake = false; } // The precise ordering of start-of-level made me want to cut my head off, From c2bab86d7009c49334f64501e40291a475d1be76 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 5 Aug 2025 19:06:46 -0400 Subject: [PATCH 45/46] Stable sort suicide store --- src/k_grandprix.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 8c88de5fa..041d092f8 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -163,8 +163,8 @@ static boolean CompareRivals(player_t *a, player_t *b) return (K_RivalScore(a) > K_RivalScore(b)); } - // They are equals, so just randomize - return (P_Random(PR_BOTS) & 1); + // Fuck it + return a > b; } void K_AssignFoes(void) @@ -749,8 +749,8 @@ static boolean CompareJoiners(player_t *a, player_t *b) return (a->spectatewait < b->spectatewait); } - // They are equals, so just randomize - return (P_Random(PR_BOTS) & 1); + // Fuck it + return a > b; } static boolean CompareReplacements(player_t *a, player_t *b) @@ -767,8 +767,8 @@ static boolean CompareReplacements(player_t *a, player_t *b) return (a->position < b->position); } - // They are equals, so just randomize - return (P_Random(PR_BOTS) & 1); + // Fuck it + return a > b; } /*-------------------------------------------------- From 77ee717952dafd0dab928807e9ca46ae07e1f3da Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 6 Aug 2025 16:38:54 -0400 Subject: [PATCH 46/46] WIP: End distance EXP scaling --- src/k_bot.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 251f0f3c8..d8da81725 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -819,7 +819,13 @@ fixed_t K_BotRubberband(const player_t *player) scaled_dist = FixedDiv(scaled_dist, mapobjectscale); } - constexpr UINT32 END_DIST = 2048 * 14; + UINT32 END_DIST = 2048 * 14; + + if (K_EffectiveGradingFactor(player) <= FRACUNIT) + { + END_DIST = Easing_Linear((K_EffectiveGradingFactor(player) - MINGRADINGFACTOR) * 2, END_DIST * 2, END_DIST); + } + if (scaled_dist < END_DIST) { // At the end of tracks, start slowing down. @@ -837,7 +843,7 @@ fixed_t K_BotRubberband(const player_t *player) fixed_t K_UpdateRubberband(player_t *player) { fixed_t dest = K_BotRubberband(player); - + fixed_t deflect = player->botvars.recentDeflection; if (deflect > BOTMAXDEFLECTION) deflect = BOTMAXDEFLECTION; @@ -2160,7 +2166,7 @@ void K_UpdateBotGameplayVars(player_t *player) UINT32 smo = BOTANGLESAMPLES - 1; player->botvars.recentDeflection = (smo * player->botvars.recentDeflection / BOTANGLESAMPLES) + (dangle / BOTANGLESAMPLES); - + player->botvars.lastAngle = mangle; const botcontroller_t *botController = K_GetBotController(player->mo);