mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-30 11:42:48 +00:00
Merge branch 'lua-roulette' into 'master'
Lua itemroulette stuff from public (JugadorXEI) See merge request kart-krew-dev/ring-racers-internal!2671
This commit is contained in:
commit
d6eef24f83
17 changed files with 1209 additions and 196 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -508,22 +508,24 @@ 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
|
||||
{
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -5248,6 +5248,21 @@ 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},
|
||||
|
||||
// itemflags_t
|
||||
{"IF_USERINGS", IF_USERINGS},
|
||||
{"IF_ITEMOUT", IF_ITEMOUT},
|
||||
{"IF_EGGMANOUT", IF_EGGMANOUT},
|
||||
{"IF_HOLDREADY", IF_HOLDREADY},
|
||||
|
||||
// kartshields_t
|
||||
{"KSHIELD_NONE",KSHIELD_NONE},
|
||||
|
|
|
|||
|
|
@ -1863,7 +1863,7 @@ static void K_UpdateBotGameplayVarsItemUsageMash(player_t *player)
|
|||
else
|
||||
{
|
||||
botItemPriority_e currentPriority = K_GetBotItemPriority(
|
||||
static_cast<kartitems_t>( player->itemRoulette.itemList[ player->itemRoulette.index ] )
|
||||
static_cast<kartitems_t>( 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<kartitems_t>( player->itemRoulette.itemList[i] ) );
|
||||
botItemPriority_e priority = K_GetBotItemPriority( static_cast<kartitems_t>( player->itemRoulette.itemList.items[i] ) );
|
||||
|
||||
if (priority < BOT_ITEM_PR__OVERRIDES)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1630,15 +1630,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);
|
||||
|
|
@ -1825,7 +1825,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);
|
||||
}
|
||||
|
|
@ -2144,15 +2144,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);
|
||||
}
|
||||
|
|
@ -7202,7 +7202,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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,9 @@ boolean K_InRaceDuel(void)
|
|||
|
||||
fixed_t K_EffectiveGradingFactor(const player_t *player)
|
||||
{
|
||||
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))
|
||||
return min;
|
||||
|
|
|
|||
250
src/k_roulette.c
250
src/k_roulette.c
|
|
@ -404,17 +404,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;
|
||||
|
|
@ -467,7 +459,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.
|
||||
|
|
@ -480,10 +472,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)
|
||||
{
|
||||
|
|
@ -498,24 +488,13 @@ 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;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
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)
|
||||
{
|
||||
|
|
@ -567,7 +546,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))
|
||||
{
|
||||
|
|
@ -579,19 +558,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;
|
||||
|
|
@ -704,18 +675,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)
|
||||
{
|
||||
|
|
@ -778,23 +740,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 = 32;
|
||||
roulette->itemList.items = Z_Calloc(
|
||||
sizeof(SINT8) * roulette->itemList.cap,
|
||||
PU_STATIC,
|
||||
&roulette->itemList
|
||||
NULL
|
||||
);
|
||||
|
||||
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;
|
||||
|
|
@ -860,74 +822,65 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
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->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->ringbox && item >= NUMKARTRESULTS)
|
||||
{
|
||||
roulette->itemListCap *= 2;
|
||||
roulette->itemList = Z_Realloc(
|
||||
roulette->itemList,
|
||||
sizeof(SINT8) * roulette->itemListCap,
|
||||
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;
|
||||
roulette->itemList.items = Z_Realloc(
|
||||
roulette->itemList.items,
|
||||
sizeof(SINT8) * roulette->itemList.cap,
|
||||
PU_STATIC,
|
||||
&roulette->itemList
|
||||
NULL
|
||||
);
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
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)
|
||||
{
|
||||
if (player && K_PlayerUsesBotMovement(player) && !K_BotUnderstandsItem(item))
|
||||
return;
|
||||
|
|
@ -951,19 +904,11 @@ static void K_AddItemToReel(const player_t *player, itemroulette_t *const roulet
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
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;
|
||||
|
|
@ -1244,7 +1189,7 @@ static boolean K_TimingPermitsItem(kartitems_t item, const itemroulette_t *roule
|
|||
|
||||
static void K_FixEmptyRoulette(const player_t *player, itemroulette_t *const roulette)
|
||||
{
|
||||
if (roulette->itemListLen > 0)
|
||||
if (roulette->itemList.len > 0)
|
||||
return;
|
||||
|
||||
if (K_PlayerUsesBotMovement(player)) // Bots can't use certain items. Give them _something_.
|
||||
|
|
@ -1254,21 +1199,12 @@ static void K_FixEmptyRoulette(const player_t *player, itemroulette_t *const rou
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun)
|
||||
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun)
|
||||
void K_FillItemRoulette(player_t *const player, itemroulette_t *const roulette, boolean ringbox)
|
||||
{
|
||||
UINT32 spawnChance[NUMKARTRESULTS] = {0};
|
||||
UINT32 totalSpawnChance = 0;
|
||||
size_t rngRoll = 0;
|
||||
|
||||
UINT8 numItems = 0;
|
||||
kartitems_t singleItem = KITEM_SAD;
|
||||
|
||||
size_t i, j;
|
||||
|
||||
K_InitRoulette(roulette);
|
||||
|
||||
if (player != NULL)
|
||||
|
|
@ -1281,6 +1217,49 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
|
|||
K_CalculateRouletteSpeed(roulette);
|
||||
}
|
||||
|
||||
// Lua may want to intercept reelbuilder entirely.
|
||||
LUA_HookPreFillItemRoulette(player, roulette, ringbox);
|
||||
|
||||
// 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, ringbox);
|
||||
|
||||
// If somehow there's no items, add sad.
|
||||
if (roulette->itemList.len == 0) {
|
||||
if (roulette->ringbox)
|
||||
K_PushToRouletteItemList(roulette, KSM_BAR);
|
||||
else
|
||||
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(player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun)
|
||||
{
|
||||
UINT32 spawnChance[NUMKARTRESULTS] = {0};
|
||||
UINT32 totalSpawnChance = 0;
|
||||
size_t rngRoll = 0;
|
||||
|
||||
UINT8 numItems = 0;
|
||||
kartitems_t singleItem = KITEM_SAD;
|
||||
|
||||
size_t i, j;
|
||||
|
||||
if (roulette->itemList.items == NULL)
|
||||
{
|
||||
K_InitRoulette(roulette);
|
||||
}
|
||||
|
||||
if (ringbox == true)
|
||||
{
|
||||
// If this is being invoked by a Ring Box, it should literally never produce items.
|
||||
|
|
@ -1313,6 +1292,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
|
|||
{
|
||||
K_PushToRouletteItemList(roulette, K_KartItemReelSpecialEnd[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1792,10 +1772,10 @@ 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->itemListLen - 1);
|
||||
roulette->index = P_RandomRange(PR_AUTOROULETTE, 0, roulette->itemList.len - 1);
|
||||
|
||||
if (K_PlayerUsesBotMovement(player) == true)
|
||||
{
|
||||
|
|
@ -1804,9 +1784,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);
|
||||
|
|
@ -1880,19 +1860,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)
|
||||
{
|
||||
|
|
@ -1935,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
|
||||
)
|
||||
{
|
||||
|
|
@ -2000,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
|
||||
|
|
@ -2012,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)
|
||||
{
|
||||
|
|
@ -2057,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.
|
||||
|
|
@ -2070,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);
|
||||
|
|
|
|||
155
src/k_roulette.h
155
src/k_roulette.h
|
|
@ -76,6 +76,90 @@ 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)
|
||||
|
||||
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);
|
||||
|
||||
/*--------------------------------------------------
|
||||
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);
|
||||
|
|
@ -96,9 +180,27 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result);
|
|||
|
||||
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(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
|
||||
|
|
@ -116,7 +218,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);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -224,8 +326,57 @@ fixed_t K_GetSlotOffset(itemroulette_t *const roulette, fixed_t renderDelta, UIN
|
|||
|
||||
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);
|
||||
|
||||
/*--------------------------------------------------
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -46,6 +47,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!");\
|
||||
|
|
@ -232,6 +234,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}
|
||||
};
|
||||
|
||||
|
|
@ -3920,6 +3924,68 @@ 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_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, NULL));
|
||||
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_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));
|
||||
|
|
@ -4014,6 +4080,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);
|
||||
|
|
@ -4057,6 +4129,419 @@ 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_kAddItemToReel(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
|
||||
NOHUD
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
itemRoulette = &player->itemRoulette;
|
||||
|
||||
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 = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
NOHUD
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
itemRoulette = &player->itemRoulette;
|
||||
|
||||
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_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_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_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_kFillItemRouletteData(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
|
||||
boolean ringbox = lua_optboolean(L, 2);
|
||||
|
||||
NOHUD
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
itemRoulette = &player->itemRoulette;
|
||||
|
||||
K_FillItemRouletteData(player, itemRoulette, ringbox, false);
|
||||
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_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_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_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 = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
|
||||
NOHUD
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
itemRoulette = &player->itemRoulette;
|
||||
|
||||
itemRoulette->itemList.len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_kSetItemInReelByIndex(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
kartitems_t item = luaL_checkinteger(L, 3);
|
||||
|
||||
NOHUD
|
||||
INLEVEL
|
||||
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.");
|
||||
|
||||
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 = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
|
||||
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)
|
||||
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) {
|
||||
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 = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
itemroulette_t *itemRoulette = NULL;
|
||||
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
|
||||
NOHUD
|
||||
INLEVEL
|
||||
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.");
|
||||
|
||||
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_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));
|
||||
|
|
@ -4326,9 +4811,15 @@ 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_ItemResultToType",lib_kItemResultToType},
|
||||
{"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},
|
||||
|
|
@ -4339,9 +4830,39 @@ 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},
|
||||
|
||||
// k_roulette
|
||||
{"K_ItemEnabled", lib_kItemEnabled},
|
||||
{"K_ItemSingularity", lib_kItemSingularity},
|
||||
{"K_GetBotItemPriority", lib_kGetBotItemPriority},
|
||||
{"K_AddItemToReel", lib_kAddItemToReel},
|
||||
{"K_PushToRouletteItemList", lib_kPushToRouletteItemList},
|
||||
{"K_StartItemRoulette", lib_kStartItemRoulette},
|
||||
{"K_StartEggmanRoulette", lib_kStartEggmanRoulette},
|
||||
{"K_StopRoulette", lib_kStopRoulette},
|
||||
{"K_KartGetItemResult", lib_kKartGetItemResult},
|
||||
{"K_GetItemRouletteDistance", lib_kGetItemRouletteDistance},
|
||||
{"K_FillItemRouletteData", lib_kFillItemRouletteData},
|
||||
{"K_ForcedSPB", lib_kForcedSPB},
|
||||
{"K_DenyShieldOdds", lib_kDenyShieldOdds},
|
||||
{"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},
|
||||
{"K_SetItemInReelByIndex", lib_kSetItemInReelByIndex},
|
||||
{"K_AddItemToReelByIndex", lib_kAddItemToReelByIndex},
|
||||
{"K_RemoveItemFromReelByIndex", lib_kRemoveItemFromReelByIndex},
|
||||
|
||||
// k_grandprix
|
||||
{"K_CanChangeRules", lib_kCanChangeRules},
|
||||
|
||||
// hu_stuff technically?
|
||||
{"HU_DoTitlecardCEcho", lib_startTitlecardCecho},
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ automatically.
|
|||
X (GameQuit),\
|
||||
X (PlayerCmd),/* building the player's ticcmd struct */\
|
||||
X (VoteThinker),/* Y_VoteTicker */\
|
||||
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),\
|
||||
|
|
@ -146,6 +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, boolean ringbox);
|
||||
int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "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,39 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
int LUA_HookFillItemRoulette(player_t *player, itemroulette_t *const roulette, boolean ringbox)
|
||||
{
|
||||
return roulette_hook(player, roulette, ringbox, HOOK(FillItemRoulette), res_true);
|
||||
}
|
||||
|
||||
boolean hook_cmd_running = false;
|
||||
|
|
|
|||
276
src/lua_itemroulettelib.c
Normal file
276
src/lua_itemroulettelib.c
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
// 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_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",
|
||||
"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_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_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 (!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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -438,10 +440,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"))
|
||||
|
|
@ -799,6 +799,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));
|
||||
|
|
@ -1083,10 +1085,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"))
|
||||
|
|
|
|||
27
src/lua_playerlib.h
Normal file
27
src/lua_playerlib.h
Normal file
|
|
@ -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__
|
||||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
@ -894,6 +895,7 @@ void LUA_InvalidatePlayer(player_t *player)
|
|||
LUA_InvalidateUserdata(player);
|
||||
LUA_InvalidateUserdata(player->karthud);
|
||||
LUA_InvalidateUserdata(&player->cmd);
|
||||
LUA_InvalidateUserdata(&player->itemRoulette.itemList);
|
||||
}
|
||||
|
||||
enum
|
||||
|
|
|
|||
|
|
@ -782,33 +782,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
|
||||
|
|
@ -1447,44 +1447,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 = (SINT8*)Z_Calloc(
|
||||
sizeof(SINT8) * players[i].itemRoulette.itemList.cap,
|
||||
PU_STATIC,
|
||||
&players[i].itemRoulette.itemList
|
||||
NULL
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
players[i].itemRoulette.itemList = Z_Realloc(
|
||||
players[i].itemRoulette.itemList,
|
||||
sizeof(SINT8) * players[i].itemRoulette.itemListCap,
|
||||
players[i].itemRoulette.itemList.items = (SINT8*)Z_Realloc(
|
||||
players[i].itemRoulette.itemList.items,
|
||||
sizeof(SINT8) * players[i].itemRoulette.itemList.cap,
|
||||
PU_STATIC,
|
||||
&players[i].itemRoulette.itemList
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue