mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge remote-tracking branch 'origin/master' into ta-rebalance-gaiden
This commit is contained in:
commit
fad24db244
23 changed files with 1381 additions and 260 deletions
|
|
@ -123,6 +123,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
||||||
lua_hudlib.c
|
lua_hudlib.c
|
||||||
lua_hudlib_drawlist.c
|
lua_hudlib_drawlist.c
|
||||||
lua_followerlib.c
|
lua_followerlib.c
|
||||||
|
lua_itemroulettelib.c
|
||||||
lua_profile.cpp
|
lua_profile.cpp
|
||||||
k_kart.c
|
k_kart.c
|
||||||
k_respawn.c
|
k_respawn.c
|
||||||
|
|
|
||||||
|
|
@ -426,6 +426,7 @@ struct botvars_t
|
||||||
UINT8 difficulty; // Bot's difficulty setting
|
UINT8 difficulty; // Bot's difficulty setting
|
||||||
INT16 diffincrease; // In GP: bot difficulty will increase this much next round
|
INT16 diffincrease; // In GP: bot difficulty will increase this much next round
|
||||||
boolean rival; // If true, they're the GP rival
|
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
|
// All entries above persist between rounds and must be recorded in demos
|
||||||
|
|
||||||
|
|
@ -516,22 +517,24 @@ struct skybox_t {
|
||||||
|
|
||||||
// player_t struct for item roulette variables
|
// player_t struct for item roulette variables
|
||||||
|
|
||||||
// Doing this the right way is causing problems.
|
// In case of dynamic alloc failure, break glass:
|
||||||
// so FINE, it's a static length now.
|
// #define ITEM_LIST_SIZE (NUMKARTRESULTS << 3)
|
||||||
#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
|
struct itemroulette_t
|
||||||
{
|
{
|
||||||
boolean active;
|
boolean active;
|
||||||
|
itemlist_t itemList;
|
||||||
#ifdef ITEM_LIST_SIZE
|
|
||||||
size_t itemListLen;
|
|
||||||
SINT8 itemList[ITEM_LIST_SIZE];
|
|
||||||
#else
|
|
||||||
size_t itemListCap;
|
|
||||||
size_t itemListLen;
|
|
||||||
SINT8 *itemList;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UINT8 playing, exiting;
|
UINT8 playing, exiting;
|
||||||
UINT32 preexpdist, dist, baseDist;
|
UINT32 preexpdist, dist, baseDist;
|
||||||
|
|
|
||||||
|
|
@ -5248,6 +5248,21 @@ struct int_const_s const INT_CONST[] = {
|
||||||
{"ENDOFPOWERUPS",ENDOFPOWERUPS},
|
{"ENDOFPOWERUPS",ENDOFPOWERUPS},
|
||||||
{"LASTPOWERUP",LASTPOWERUP},
|
{"LASTPOWERUP",LASTPOWERUP},
|
||||||
{"NUMPOWERUPS",NUMPOWERUPS},
|
{"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
|
// kartshields_t
|
||||||
{"KSHIELD_NONE",KSHIELD_NONE},
|
{"KSHIELD_NONE",KSHIELD_NONE},
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ void G_ReadDemoExtraData(void)
|
||||||
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
||||||
players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic
|
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.rival = (boolean)READUINT8(demobuf.p);
|
||||||
|
players[p].botvars.foe = (boolean)READUINT8(demobuf.p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (extradata & DXD_PLAYSTATE)
|
if (extradata & DXD_PLAYSTATE)
|
||||||
|
|
@ -497,6 +498,7 @@ void G_WriteDemoExtraData(void)
|
||||||
WRITEUINT8(demobuf.p, players[i].botvars.difficulty);
|
WRITEUINT8(demobuf.p, players[i].botvars.difficulty);
|
||||||
WRITEINT16(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic
|
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.rival);
|
||||||
|
WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.foe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (demo_extradata[i] & DXD_PLAYSTATE)
|
if (demo_extradata[i] & DXD_PLAYSTATE)
|
||||||
|
|
@ -2132,6 +2134,7 @@ void G_BeginRecording(void)
|
||||||
WRITEUINT8(demobuf.p, player->botvars.difficulty);
|
WRITEUINT8(demobuf.p, player->botvars.difficulty);
|
||||||
WRITEINT16(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic
|
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.rival);
|
||||||
|
WRITEUINT8(demobuf.p, (UINT8)player->botvars.foe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
|
|
@ -3315,6 +3318,7 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
|
||||||
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
||||||
players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic
|
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.rival = (boolean)READUINT8(demobuf.p);
|
||||||
|
players[p].botvars.foe = (boolean)READUINT8(demobuf.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
K_UpdateShrinkCheat(&players[p]);
|
K_UpdateShrinkCheat(&players[p]);
|
||||||
|
|
|
||||||
|
|
@ -2271,6 +2271,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
|
|
||||||
INT16 botdiffincrease;
|
INT16 botdiffincrease;
|
||||||
boolean botrival;
|
boolean botrival;
|
||||||
|
boolean botfoe;
|
||||||
|
|
||||||
boolean cangrabitems;
|
boolean cangrabitems;
|
||||||
|
|
||||||
|
|
@ -2381,6 +2382,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
|
|
||||||
botdiffincrease = players[player].botvars.diffincrease;
|
botdiffincrease = players[player].botvars.diffincrease;
|
||||||
botrival = players[player].botvars.rival;
|
botrival = players[player].botvars.rival;
|
||||||
|
botfoe = players[player].botvars.foe;
|
||||||
|
|
||||||
totalring = players[player].totalring;
|
totalring = players[player].totalring;
|
||||||
xtralife = players[player].xtralife;
|
xtralife = players[player].xtralife;
|
||||||
|
|
@ -2641,6 +2643,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
p->spheres = spheres;
|
p->spheres = spheres;
|
||||||
p->botvars.diffincrease = botdiffincrease;
|
p->botvars.diffincrease = botdiffincrease;
|
||||||
p->botvars.rival = botrival;
|
p->botvars.rival = botrival;
|
||||||
|
p->botvars.foe = botfoe;
|
||||||
p->xtralife = xtralife;
|
p->xtralife = xtralife;
|
||||||
|
|
||||||
// SRB2kart
|
// SRB2kart
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,8 @@ void K_UpdateMatchRaceBots(void)
|
||||||
clear_bots(wantedbots);
|
clear_bots(wantedbots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_AssignFoes();
|
||||||
|
|
||||||
// We should have enough bots now :)
|
// We should have enough bots now :)
|
||||||
|
|
||||||
#ifdef HAVE_DISCORDRPC
|
#ifdef HAVE_DISCORDRPC
|
||||||
|
|
@ -615,7 +617,7 @@ fixed_t K_BotMapModifier(void)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
static UINT32 K_BotRubberbandDistance(const player_t *player)
|
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;
|
const UINT8 portpriority = player - players;
|
||||||
UINT8 pos = 1;
|
UINT8 pos = 1;
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
@ -626,6 +628,11 @@ static UINT32 K_BotRubberbandDistance(const player_t *player)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (player->botvars.foe)
|
||||||
|
spacing /= 2;
|
||||||
|
*/
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (i == portpriority)
|
if (i == portpriority)
|
||||||
|
|
@ -649,6 +656,11 @@ static UINT32 K_BotRubberbandDistance(const player_t *player)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (player->botvars.foe && !players[i].botvars.foe)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// First check difficulty levels, then score, then settle it with port priority!
|
// First check difficulty levels, then score, then settle it with port priority!
|
||||||
if (player->botvars.difficulty < players[i].botvars.difficulty)
|
if (player->botvars.difficulty < players[i].botvars.difficulty)
|
||||||
{
|
{
|
||||||
|
|
@ -694,6 +706,8 @@ fixed_t K_BotRubberband(const player_t *player)
|
||||||
{
|
{
|
||||||
UINT8 levelreduce = std::min<UINT8>(3, player->botvars.difficulty/4); // How much to drop the "effective level" of bots that are consistently behind
|
UINT8 levelreduce = std::min<UINT8>(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);
|
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);
|
fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1);
|
||||||
|
|
@ -805,7 +819,13 @@ fixed_t K_BotRubberband(const player_t *player)
|
||||||
scaled_dist = FixedDiv(scaled_dist, mapobjectscale);
|
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)
|
if (scaled_dist < END_DIST)
|
||||||
{
|
{
|
||||||
// At the end of tracks, start slowing down.
|
// At the end of tracks, start slowing down.
|
||||||
|
|
@ -823,7 +843,7 @@ fixed_t K_BotRubberband(const player_t *player)
|
||||||
fixed_t K_UpdateRubberband(player_t *player)
|
fixed_t K_UpdateRubberband(player_t *player)
|
||||||
{
|
{
|
||||||
fixed_t dest = K_BotRubberband(player);
|
fixed_t dest = K_BotRubberband(player);
|
||||||
|
|
||||||
fixed_t deflect = player->botvars.recentDeflection;
|
fixed_t deflect = player->botvars.recentDeflection;
|
||||||
if (deflect > BOTMAXDEFLECTION)
|
if (deflect > BOTMAXDEFLECTION)
|
||||||
deflect = BOTMAXDEFLECTION;
|
deflect = BOTMAXDEFLECTION;
|
||||||
|
|
@ -2146,7 +2166,7 @@ void K_UpdateBotGameplayVars(player_t *player)
|
||||||
UINT32 smo = BOTANGLESAMPLES - 1;
|
UINT32 smo = BOTANGLESAMPLES - 1;
|
||||||
|
|
||||||
player->botvars.recentDeflection = (smo * player->botvars.recentDeflection / BOTANGLESAMPLES) + (dangle / BOTANGLESAMPLES);
|
player->botvars.recentDeflection = (smo * player->botvars.recentDeflection / BOTANGLESAMPLES) + (dangle / BOTANGLESAMPLES);
|
||||||
|
|
||||||
player->botvars.lastAngle = mangle;
|
player->botvars.lastAngle = mangle;
|
||||||
|
|
||||||
const botcontroller_t *botController = K_GetBotController(player->mo);
|
const botcontroller_t *botController = K_GetBotController(player->mo);
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ static boolean K_RivalBotAggression(const player_t *bot, const player_t *target)
|
||||||
return false;
|
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.
|
// Not the rival, we aren't self-aware.
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1863,7 +1863,7 @@ static void K_UpdateBotGameplayVarsItemUsageMash(player_t *player)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
botItemPriority_e currentPriority = K_GetBotItemPriority(
|
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)
|
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.
|
// reduce priority until we get to a valid one.
|
||||||
player->botvars.rouletteTimeout++;
|
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.roulettePriority--;
|
||||||
player->botvars.rouletteTimeout = 0;
|
player->botvars.rouletteTimeout = 0;
|
||||||
|
|
@ -1995,9 +1995,9 @@ void K_BotPickItemPriority(player_t *player)
|
||||||
player->botvars.rouletteTimeout = 0;
|
player->botvars.rouletteTimeout = 0;
|
||||||
|
|
||||||
// Check for items that are extremely high priority.
|
// 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)
|
if (priority < BOT_ITEM_PR__OVERRIDES)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,113 @@ static UINT8 K_GetOffsetStartingDifficulty(const UINT8 startingdifficulty, UINT8
|
||||||
return startingdifficulty - offset;
|
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)
|
||||||
|
{
|
||||||
|
if (a == NULL)
|
||||||
|
return false;
|
||||||
|
if (b == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (K_RivalScore(a) != K_RivalScore(b))
|
||||||
|
{
|
||||||
|
// Rival Score is HIGH when bots are strong. Sort them first!
|
||||||
|
return (K_RivalScore(a) > K_RivalScore(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fuck it
|
||||||
|
return a > b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_AssignFoes(void)
|
||||||
|
{
|
||||||
|
std::vector<player_t *> bots;
|
||||||
|
boolean addedplayer = false;
|
||||||
|
|
||||||
|
for (UINT8 i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (playeringame[i] == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
player_t *player = &players[i];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i > 2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_InitGrandPrixBots(void)
|
void K_InitGrandPrixBots(void)
|
||||||
|
|
||||||
|
|
@ -254,6 +361,8 @@ void K_InitGrandPrixBots(void)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (i <= 2)
|
||||||
|
players[newplayernum-1].botvars.foe = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,64 +398,13 @@ void K_LoadGrandPrixSaveGame(void)
|
||||||
K_SetBot(i, savedata.bots[i].skin, savedata.bots[i].difficulty, BOT_STYLE_NORMAL);
|
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.rival = savedata.bots[i].rival;
|
||||||
|
players[i].botvars.foe = savedata.bots[i].foe;
|
||||||
players[i].score = savedata.bots[i].score;
|
players[i].score = savedata.bots[i].score;
|
||||||
|
|
||||||
players[i].spectator = K_BotDefaultSpectator();
|
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)
|
void K_UpdateGrandPrixBots(void)
|
||||||
|
|
||||||
|
|
@ -379,6 +437,8 @@ void K_UpdateGrandPrixBots(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_AssignFoes();
|
||||||
|
|
||||||
// Find the rival.
|
// Find the rival.
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -639,7 +699,7 @@ void K_IncreaseBotDifficulty(player_t *bot)
|
||||||
// RELAXED MODE:
|
// RELAXED MODE:
|
||||||
// Continues don't drop bot difficulty, because we always advance.
|
// Continues don't drop bot difficulty, because we always advance.
|
||||||
// Bots will still level up from standard advancement; we need a
|
// 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)
|
if (grandprixinfo.gamespeed == KARTSPEED_EASY)
|
||||||
{
|
{
|
||||||
switch(averageRank)
|
switch(averageRank)
|
||||||
|
|
@ -689,8 +749,8 @@ static boolean CompareJoiners(player_t *a, player_t *b)
|
||||||
return (a->spectatewait < b->spectatewait);
|
return (a->spectatewait < b->spectatewait);
|
||||||
}
|
}
|
||||||
|
|
||||||
// They are equals, so just randomize
|
// Fuck it
|
||||||
return (P_Random(PR_BOTS) & 1);
|
return a > b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean CompareReplacements(player_t *a, player_t *b)
|
static boolean CompareReplacements(player_t *a, player_t *b)
|
||||||
|
|
@ -707,8 +767,8 @@ static boolean CompareReplacements(player_t *a, player_t *b)
|
||||||
return (a->position < b->position);
|
return (a->position < b->position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// They are equals, so just randomize
|
// Fuck it
|
||||||
return (P_Random(PR_BOTS) & 1);
|
return a > b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,8 @@ boolean K_CanChangeRules(boolean allowdemos);
|
||||||
|
|
||||||
boolean K_BotDefaultSpectator(void);
|
boolean K_BotDefaultSpectator(void);
|
||||||
|
|
||||||
|
void K_AssignFoes(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -1630,15 +1630,15 @@ static void K_drawKartItem(void)
|
||||||
boolean flashOnOne = false;
|
boolean flashOnOne = false;
|
||||||
boolean flashOnTwo = false;
|
boolean flashOnTwo = false;
|
||||||
|
|
||||||
if (stplyr->itemRoulette.itemListLen > 0)
|
if (stplyr->itemRoulette.itemList.len > 0)
|
||||||
{
|
{
|
||||||
// Init with item roulette stuff.
|
// Init with item roulette stuff.
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
const SINT8 indexOfs = i-1;
|
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 SINT8 item = K_ItemResultToType(result);
|
||||||
const boolean usingDebugItemAmount = cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == item && cv_kartdebugamount.value > 1;
|
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);
|
const UINT8 amt = usingDebugItemAmount ? cv_kartdebugamount.value : K_ItemResultToAmount(result, &stplyr->itemRoulette);
|
||||||
|
|
@ -1825,7 +1825,7 @@ static void K_drawKartItem(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 *boxmap = NULL;
|
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);
|
boxmap = R_GetTranslationColormap(TC_ALLWHITE, SKINCOLOR_WHITE, GTC_CACHE);
|
||||||
}
|
}
|
||||||
|
|
@ -2144,15 +2144,15 @@ static void K_drawKartSlotMachine(void)
|
||||||
vector2_t rouletteCrop = {10, 10};
|
vector2_t rouletteCrop = {10, 10};
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
|
||||||
if (stplyr->itemRoulette.itemListLen > 0)
|
if (stplyr->itemRoulette.itemList.len > 0)
|
||||||
{
|
{
|
||||||
// Init with item roulette stuff.
|
// Init with item roulette stuff.
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
const SINT8 indexOfs = i-1;
|
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);
|
localpatch[i] = K_GetCachedSlotMachinePatch(result, offset);
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
K_DrawNameTagItemSpy(barx, bary, p, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT8 *foecol = R_GetTranslationColormap(TC_RAINBOW, static_cast<skincolornum_t>(SKINCOLOR_RED), GTC_CACHE);
|
||||||
|
|
||||||
UINT8 blink = ((leveltime / 7) & 1);
|
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)
|
static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flags)
|
||||||
|
|
@ -7202,7 +7204,7 @@ static void K_drawDistributionDebugger(void)
|
||||||
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+58, V_SNAPTOTOP|V_SNAPTORIGHT, va("secondToFirst = %u", rouletteData.secondToFirst));
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+58, V_SNAPTOTOP|V_SNAPTORIGHT, va("secondToFirst = %u", rouletteData.secondToFirst));
|
||||||
|
|
||||||
#ifndef ITEM_LIST_SIZE
|
#ifndef ITEM_LIST_SIZE
|
||||||
Z_Free(rouletteData.itemList);
|
Z_Free(rouletteData.itemList.items);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7314,7 +7316,7 @@ static void K_DrawBotDebugger(void)
|
||||||
|
|
||||||
V_DrawSmallString(8, 14, 0, va("Difficulty: %d / %d", bot->botvars.difficulty, MAXBOTDIFFICULTY));
|
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, 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, 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));
|
V_DrawSmallString(8, 32, 0, va("Item delay: %d", bot->botvars.itemdelay));
|
||||||
|
|
|
||||||
14
src/k_kart.c
14
src/k_kart.c
|
|
@ -145,6 +145,9 @@ boolean K_InRaceDuel(void)
|
||||||
|
|
||||||
fixed_t K_EffectiveGradingFactor(const player_t *player)
|
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;
|
fixed_t min = (franticitems) ? MINFRANTICFACTOR : MINGRADINGFACTOR;
|
||||||
if (grandprixinfo.gp && grandprixinfo.masterbots && !K_PlayerUsesBotMovement(player))
|
if (grandprixinfo.gp && grandprixinfo.masterbots && !K_PlayerUsesBotMovement(player))
|
||||||
return min;
|
return min;
|
||||||
|
|
@ -1622,6 +1625,8 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed
|
||||||
// Double speed for the rival!
|
// Double speed for the rival!
|
||||||
if (player->botvars.rival || cv_levelskull.value)
|
if (player->botvars.rival || cv_levelskull.value)
|
||||||
player->draftpower += add;
|
player->draftpower += add;
|
||||||
|
else if (player->botvars.foe)
|
||||||
|
player->draftpower += add/2;
|
||||||
else if (dest->player->bot) // Reduce bot gluts.
|
else if (dest->player->bot) // Reduce bot gluts.
|
||||||
player->draftpower -= 3*add/4;
|
player->draftpower -= 3*add/4;
|
||||||
}
|
}
|
||||||
|
|
@ -3558,6 +3563,10 @@ static fixed_t K_RingDurationBoost(const player_t *player)
|
||||||
// x2.0 for Rival
|
// x2.0 for Rival
|
||||||
ret *= 2;
|
ret *= 2;
|
||||||
}
|
}
|
||||||
|
else if (player->botvars.foe)
|
||||||
|
{
|
||||||
|
ret = 3 * ret / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -3980,6 +3989,11 @@ fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dor
|
||||||
// +10% top speed for the rival
|
// +10% top speed for the rival
|
||||||
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
|
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
|
||||||
}
|
}
|
||||||
|
else if (player->bot && player->botvars.foe)
|
||||||
|
{
|
||||||
|
// +5% for foes
|
||||||
|
finalspeed = FixedMul(finalspeed, 21*FRACUNIT/20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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)
|
static fixed_t K_ItemOddsScale(UINT8 playerCount)
|
||||||
|
|
||||||
A multiplier for odds and distances to scale
|
See header file for description.
|
||||||
them with the player count.
|
|
||||||
|
|
||||||
Input Arguments:-
|
|
||||||
playerCount - Number of players in the game.
|
|
||||||
|
|
||||||
Return:-
|
|
||||||
Fixed point number, to multiply odds or
|
|
||||||
distances by.
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
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.
|
const UINT8 basePlayer = 8; // The player count we design most of the game around.
|
||||||
fixed_t playerScaling = 0;
|
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
|
Adjust item distance for lobby-size scaling
|
||||||
as well as Frantic Items.
|
as well as Frantic Items.
|
||||||
|
|
@ -480,10 +472,8 @@ static UINT32 K_UndoMapScaling(UINT32 distance)
|
||||||
Return:-
|
Return:-
|
||||||
New distance after scaling.
|
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 0
|
||||||
if (franticitems == true)
|
if (franticitems == true)
|
||||||
{
|
{
|
||||||
|
|
@ -498,24 +488,13 @@ static UINT32 K_ScaleItemDistance(const player_t *player, UINT32 distance, UINT8
|
||||||
FRACUNIT + (K_ItemOddsScale(numPlayers) / 2)
|
FRACUNIT + (K_ItemOddsScale(numPlayers) / 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Distance is reduced based on the player's gradingfactor
|
|
||||||
// distance = FixedMul(distance, player->gradingfactor);
|
|
||||||
|
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
||||||
|
|
||||||
Gets a player's distance used for the item
|
See header file for description.
|
||||||
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)
|
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_UndoMapScaling(pdis);
|
||||||
pdis = K_ScaleItemDistance(player, pdis, numPlayers);
|
pdis = K_ScaleItemDistance(pdis, numPlayers);
|
||||||
|
|
||||||
if (player->bot && (player->botvars.rival || cv_levelskull.value))
|
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
|
See header file for description.
|
||||||
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.
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
static boolean K_DenyShieldOdds(kartitems_t item)
|
boolean K_DenyShieldOdds(kartitems_t item)
|
||||||
{
|
{
|
||||||
const INT32 shieldType = K_GetShieldFromItem(item);
|
const INT32 shieldType = K_GetShieldFromItem(item);
|
||||||
size_t i;
|
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)
|
static boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette)
|
||||||
|
|
||||||
Determines special conditions where we want
|
See header file for description.
|
||||||
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.
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
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)
|
if (K_ItemEnabled(KITEM_SPB) == false)
|
||||||
{
|
{
|
||||||
|
|
@ -778,23 +740,23 @@ static void K_InitRoulette(itemroulette_t *const roulette)
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
#ifndef ITEM_LIST_SIZE
|
#ifndef ITEM_LIST_SIZE
|
||||||
if (roulette->itemList == NULL)
|
if (roulette->itemList.items == NULL)
|
||||||
{
|
{
|
||||||
roulette->itemListCap = 8;
|
roulette->itemList.cap = 32;
|
||||||
roulette->itemList = Z_Calloc(
|
roulette->itemList.items = Z_Calloc(
|
||||||
sizeof(SINT8) * roulette->itemListCap,
|
sizeof(SINT8) * roulette->itemList.cap,
|
||||||
PU_STATIC,
|
PU_STATIC,
|
||||||
&roulette->itemList
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
if (roulette->itemList == NULL)
|
if (roulette->itemList.items == NULL)
|
||||||
{
|
{
|
||||||
I_Error("Not enough memory for item roulette list\n");
|
I_Error("Not enough memory for item roulette list\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
roulette->itemListLen = 0;
|
roulette->itemList.len = 0;
|
||||||
roulette->index = 0;
|
roulette->index = 0;
|
||||||
|
|
||||||
roulette->baseDist = roulette->dist = 0;
|
roulette->baseDist = roulette->dist = 0;
|
||||||
|
|
@ -860,74 +822,65 @@ static void K_InitRoulette(itemroulette_t *const roulette)
|
||||||
&& roulette->secondDist > roulette->firstDist)
|
&& roulette->secondDist > roulette->firstDist)
|
||||||
{
|
{
|
||||||
roulette->secondToFirst = 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
|
See header file for description.
|
||||||
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
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
static void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item)
|
void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item)
|
||||||
{
|
{
|
||||||
#ifdef ITEM_LIST_SIZE
|
#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");
|
I_Error("Out of space for item reel! Go and make ITEM_LIST_SIZE bigger I guess?\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#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;
|
CONS_Alert(CONS_WARNING, M_GetText("Item Roulette rejected an out-of-range item.\n"));
|
||||||
roulette->itemList = Z_Realloc(
|
return;
|
||||||
roulette->itemList,
|
}
|
||||||
sizeof(SINT8) * roulette->itemListCap,
|
|
||||||
|
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,
|
PU_STATIC,
|
||||||
&roulette->itemList
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
if (roulette->itemList == NULL)
|
if (roulette->itemList.items == NULL)
|
||||||
{
|
{
|
||||||
I_Error("Not enough memory for item roulette list\n");
|
I_Error("Not enough memory for item roulette list\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
roulette->itemList[ roulette->itemListLen ] = item;
|
roulette->itemList.items[ roulette->itemList.len ] = item;
|
||||||
roulette->itemListLen++;
|
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
|
See header file for description.
|
||||||
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
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
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))
|
if (player && K_PlayerUsesBotMovement(player) && !K_BotUnderstandsItem(item))
|
||||||
return;
|
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,
|
See header file for description.
|
||||||
adjusted for progress in the race and front
|
|
||||||
running.
|
|
||||||
|
|
||||||
Input Arguments:-
|
|
||||||
roulette - The item roulette data to modify.
|
|
||||||
|
|
||||||
Return:-
|
|
||||||
N/A
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
static void K_CalculateRouletteSpeed(itemroulette_t *const roulette)
|
void K_CalculateRouletteSpeed(itemroulette_t *const roulette)
|
||||||
{
|
{
|
||||||
fixed_t frontRun = 0;
|
fixed_t frontRun = 0;
|
||||||
fixed_t progress = 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)
|
static void K_FixEmptyRoulette(const player_t *player, itemroulette_t *const roulette)
|
||||||
{
|
{
|
||||||
if (roulette->itemListLen > 0)
|
if (roulette->itemList.len > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (K_PlayerUsesBotMovement(player)) // Bots can't use certain items. Give them _something_.
|
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.
|
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);
|
K_InitRoulette(roulette);
|
||||||
|
|
||||||
if (player != NULL)
|
if (player != NULL)
|
||||||
|
|
@ -1281,6 +1217,49 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
|
||||||
K_CalculateRouletteSpeed(roulette);
|
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 (ringbox == true)
|
||||||
{
|
{
|
||||||
// If this is being invoked by a Ring Box, it should literally never produce items.
|
// 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]);
|
K_PushToRouletteItemList(roulette, K_KartItemReelSpecialEnd[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1792,10 +1772,10 @@ void K_StartItemRoulette(player_t *const player, boolean ringbox)
|
||||||
itemroulette_t *const roulette = &player->itemRoulette;
|
itemroulette_t *const roulette = &player->itemRoulette;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
K_FillItemRouletteData(player, roulette, ringbox, false);
|
K_FillItemRoulette(player, roulette, ringbox);
|
||||||
|
|
||||||
if (roulette->autoroulette)
|
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)
|
if (K_PlayerUsesBotMovement(player) == true)
|
||||||
{
|
{
|
||||||
|
|
@ -1804,9 +1784,9 @@ void K_StartItemRoulette(player_t *const player, boolean ringbox)
|
||||||
|
|
||||||
// Prevent further duplicates of items that
|
// Prevent further duplicates of items that
|
||||||
// are intended to only have one out at a time.
|
// 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)
|
if (K_ItemSingularity(item) == true)
|
||||||
{
|
{
|
||||||
K_SetItemCooldown(item, TICRATE<<4);
|
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
|
See header file for description.
|
||||||
received from the roulette.
|
|
||||||
|
|
||||||
Input Arguments:-
|
|
||||||
player - The player receiving the item.
|
|
||||||
getitem - The item to give to the player.
|
|
||||||
|
|
||||||
Return:-
|
|
||||||
N/A
|
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
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)
|
if (K_ItemSingularity(getitem) == true)
|
||||||
{
|
{
|
||||||
|
|
@ -1935,9 +1907,9 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roulette->itemListLen == 0
|
if (roulette->itemList.len == 0
|
||||||
#ifndef ITEM_LIST_SIZE
|
#ifndef ITEM_LIST_SIZE
|
||||||
|| roulette->itemList == NULL
|
|| roulette->itemList.items == NULL
|
||||||
#endif
|
#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?
|
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.
|
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...
|
roulette->tics = 0; // And just in case our delay is SO high that a fast roulette needs to roll back again...
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -2012,7 +1984,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd)
|
||||||
// And one more nudge for the remaining delay.
|
// And one more nudge for the remaining delay.
|
||||||
roulette->tics = (roulette->tics + fudgedDelay) % roulette->speed;
|
roulette->tics = (roulette->tics + fudgedDelay) % roulette->speed;
|
||||||
|
|
||||||
INT32 finalItem = roulette->itemList[ roulette->index ];
|
INT32 finalItem = roulette->itemList.items[ roulette->index ];
|
||||||
|
|
||||||
if (roulette->ringbox == true)
|
if (roulette->ringbox == true)
|
||||||
{
|
{
|
||||||
|
|
@ -2057,7 +2029,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd)
|
||||||
|
|
||||||
if (roulette->tics == 0)
|
if (roulette->tics == 0)
|
||||||
{
|
{
|
||||||
roulette->index = (roulette->index + 1) % roulette->itemListLen;
|
roulette->index = (roulette->index + 1) % roulette->itemList.len;
|
||||||
roulette->tics = roulette->speed;
|
roulette->tics = roulette->speed;
|
||||||
|
|
||||||
// This makes the roulette produce the random noises.
|
// This makes the roulette produce the random noises.
|
||||||
|
|
@ -2070,7 +2042,7 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd)
|
||||||
else
|
else
|
||||||
S_StartSound(NULL, sfx_itrol1 + roulette->sound);
|
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);
|
||||||
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);
|
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);
|
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);
|
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
|
Fills out the item roulette struct when it is
|
||||||
initially created. This function needs to be
|
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
|
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_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);
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include "k_collide.h"
|
#include "k_collide.h"
|
||||||
#include "k_color.h"
|
#include "k_color.h"
|
||||||
#include "k_hud.h"
|
#include "k_hud.h"
|
||||||
|
#include "k_grandprix.h"
|
||||||
#include "d_netcmd.h" // IsPlayerAdmin
|
#include "d_netcmd.h" // IsPlayerAdmin
|
||||||
#include "k_menu.h" // Player Setup menu color stuff
|
#include "k_menu.h" // Player Setup menu color stuff
|
||||||
#include "p_spec.h" // P_StartQuake
|
#include "p_spec.h" // P_StartQuake
|
||||||
|
|
@ -46,6 +47,7 @@
|
||||||
#include "lua_hud.h" // hud_running errors
|
#include "lua_hud.h" // hud_running errors
|
||||||
#include "taglist.h" // P_FindSpecialLineFromTag
|
#include "taglist.h" // P_FindSpecialLineFromTag
|
||||||
#include "lua_hook.h" // hook_cmd_running errors
|
#include "lua_hook.h" // hook_cmd_running errors
|
||||||
|
#include "k_roulette.h"
|
||||||
|
|
||||||
#define NOHUD if (hud_running)\
|
#define NOHUD if (hud_running)\
|
||||||
return luaL_error(L, "HUD rendering code should not call this function!");\
|
return luaL_error(L, "HUD rendering code should not call this function!");\
|
||||||
|
|
@ -232,6 +234,8 @@ static const struct {
|
||||||
{META_ACTIVATOR, "activator_t"},
|
{META_ACTIVATOR, "activator_t"},
|
||||||
|
|
||||||
{META_FOLLOWER, "follower_t"},
|
{META_FOLLOWER, "follower_t"},
|
||||||
|
{META_ITEMROULETTE, "itemroulette_t"},
|
||||||
|
{META_ITEMROULETTE_ITEMLIST, "itemroulette_t.itemlist_t"},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3920,6 +3924,68 @@ static int lib_kGetItemPatch(lua_State *L)
|
||||||
return 1;
|
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)
|
static int lib_kGetCollideAngle(lua_State *L)
|
||||||
{
|
{
|
||||||
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||||
|
|
@ -4014,6 +4080,12 @@ static int lib_kDeclareWeakspot(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lib_kCheckBossIntro(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_pushboolean(L, K_CheckBossIntro());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int lib_vsGetArena(lua_State *L)
|
static int lib_vsGetArena(lua_State *L)
|
||||||
{
|
{
|
||||||
INT32 bossindex = luaL_checkinteger(L, 1);
|
INT32 bossindex = luaL_checkinteger(L, 1);
|
||||||
|
|
@ -4057,6 +4129,419 @@ static int lib_vsRandomPointOnArena(lua_State *L)
|
||||||
return 2;
|
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)
|
static int lib_getTimeMicros(lua_State *L)
|
||||||
{
|
{
|
||||||
lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000));
|
lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000));
|
||||||
|
|
@ -4326,9 +4811,15 @@ static luaL_Reg lib[] = {
|
||||||
{"K_GetKartAccel",lib_kGetKartAccel},
|
{"K_GetKartAccel",lib_kGetKartAccel},
|
||||||
{"K_GetKartFlashing",lib_kGetKartFlashing},
|
{"K_GetKartFlashing",lib_kGetKartFlashing},
|
||||||
{"K_GetItemPatch",lib_kGetItemPatch},
|
{"K_GetItemPatch",lib_kGetItemPatch},
|
||||||
|
|
||||||
{"K_GetCollideAngle",lib_kGetCollideAngle},
|
{"K_GetCollideAngle",lib_kGetCollideAngle},
|
||||||
{"K_AddHitLag",lib_kAddHitLag},
|
{"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_powerup
|
||||||
{"K_PowerUpRemaining",lib_kPowerUpRemaining},
|
{"K_PowerUpRemaining",lib_kPowerUpRemaining},
|
||||||
|
|
@ -4339,9 +4830,39 @@ static luaL_Reg lib[] = {
|
||||||
{"K_InitBossHealthBar", lib_kInitBossHealthBar},
|
{"K_InitBossHealthBar", lib_kInitBossHealthBar},
|
||||||
{"K_UpdateBossHealthBar", lib_kUpdateBossHealthBar},
|
{"K_UpdateBossHealthBar", lib_kUpdateBossHealthBar},
|
||||||
{"K_DeclareWeakspot", lib_kDeclareWeakspot},
|
{"K_DeclareWeakspot", lib_kDeclareWeakspot},
|
||||||
|
{"K_CheckBossIntro", lib_kCheckBossIntro},
|
||||||
{"VS_GetArena", lib_vsGetArena},
|
{"VS_GetArena", lib_vsGetArena},
|
||||||
{"VS_PredictAroundArena", lib_vsPredictAroundArena},
|
{"VS_PredictAroundArena", lib_vsPredictAroundArena},
|
||||||
{"VS_RandomPointOnArena", lib_vsRandomPointOnArena},
|
{"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_stuff technically?
|
||||||
{"HU_DoTitlecardCEcho", lib_startTitlecardCecho},
|
{"HU_DoTitlecardCEcho", lib_startTitlecardCecho},
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,8 @@ automatically.
|
||||||
X (GameQuit),\
|
X (GameQuit),\
|
||||||
X (PlayerCmd),/* building the player's ticcmd struct */\
|
X (PlayerCmd),/* building the player's ticcmd struct */\
|
||||||
X (VoteThinker),/* Y_VoteTicker */\
|
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) \
|
#define STRING_HOOK_LIST(X) \
|
||||||
X (SpecialExecute),\
|
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_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble);
|
||||||
int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced);
|
int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced);
|
||||||
int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend);
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "lua_hook.h"
|
#include "lua_hook.h"
|
||||||
#include "lua_hud.h" // hud_running errors
|
#include "lua_hud.h" // hud_running errors
|
||||||
#include "lua_profile.h"
|
#include "lua_profile.h"
|
||||||
|
#include "lua_playerlib.h" // constplayer
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "m_perfstats.h"
|
#include "m_perfstats.h"
|
||||||
|
|
@ -1009,4 +1010,39 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend)
|
||||||
return hook.status;
|
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;
|
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_ACTIVATOR "ACTIVATOR_T*"
|
||||||
|
|
||||||
#define META_FOLLOWER "FOLLOWER_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);
|
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_BlockmapLib(lua_State *L);
|
||||||
int LUA_HudLib(lua_State *L);
|
int LUA_HudLib(lua_State *L);
|
||||||
int LUA_FollowerLib(lua_State *L);
|
int LUA_FollowerLib(lua_State *L);
|
||||||
|
int LUA_ItemRouletteLib(lua_State *L);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
#include "lua_hook.h" // hook_cmd_running errors
|
#include "lua_hook.h" // hook_cmd_running errors
|
||||||
#include "k_profiles.h" // GetPrettyRRID
|
#include "k_profiles.h" // GetPrettyRRID
|
||||||
|
|
||||||
|
boolean constplayer = false;
|
||||||
|
|
||||||
static int lib_iteratePlayers(lua_State *L)
|
static int lib_iteratePlayers(lua_State *L)
|
||||||
{
|
{
|
||||||
INT32 i = -1;
|
INT32 i = -1;
|
||||||
|
|
@ -438,10 +440,8 @@ static int player_get(lua_State *L)
|
||||||
lua_pushinteger(L, plr->tripwireUnstuck);
|
lua_pushinteger(L, plr->tripwireUnstuck);
|
||||||
else if (fastcmp(field,"bumpunstuck"))
|
else if (fastcmp(field,"bumpunstuck"))
|
||||||
lua_pushinteger(L, plr->bumpUnstuck);
|
lua_pushinteger(L, plr->bumpUnstuck);
|
||||||
/*
|
|
||||||
else if (fastcmp(field,"itemroulette"))
|
else if (fastcmp(field,"itemroulette"))
|
||||||
lua_pushinteger(L, plr->itemroulette);
|
LUA_PushUserdata(L, &plr->itemRoulette, META_ITEMROULETTE);
|
||||||
*/
|
|
||||||
else if (fastcmp(field,"itemtype"))
|
else if (fastcmp(field,"itemtype"))
|
||||||
lua_pushinteger(L, plr->itemtype);
|
lua_pushinteger(L, plr->itemtype);
|
||||||
else if (fastcmp(field,"itemamount"))
|
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!");
|
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
|
||||||
if (hook_cmd_running)
|
if (hook_cmd_running)
|
||||||
return luaL_error(L, "Do not alter player_t in CMD building code!");
|
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")) {
|
if (fastcmp(field,"mo")) {
|
||||||
mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
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);
|
plr->tripwireUnstuck = luaL_checkinteger(L, 3);
|
||||||
else if (fastcmp(field,"bumpunstuck"))
|
else if (fastcmp(field,"bumpunstuck"))
|
||||||
plr->bumpUnstuck = luaL_checkinteger(L, 3);
|
plr->bumpUnstuck = luaL_checkinteger(L, 3);
|
||||||
/*
|
|
||||||
else if (fastcmp(field,"itemroulette"))
|
else if (fastcmp(field,"itemroulette"))
|
||||||
plr->itemroulette = luaL_checkinteger(L, 3);
|
return NOSET;
|
||||||
*/
|
|
||||||
else if (fastcmp(field,"itemtype"))
|
else if (fastcmp(field,"itemtype"))
|
||||||
plr->itemtype = luaL_checkinteger(L, 3);
|
plr->itemtype = luaL_checkinteger(L, 3);
|
||||||
else if (fastcmp(field,"itemamount"))
|
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_BlockmapLib, // blockmap stuff
|
||||||
LUA_HudLib, // HUD stuff
|
LUA_HudLib, // HUD stuff
|
||||||
LUA_FollowerLib, // follower_t, followers[]
|
LUA_FollowerLib, // follower_t, followers[]
|
||||||
|
LUA_ItemRouletteLib, // itemroulette_t
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -894,6 +895,7 @@ void LUA_InvalidatePlayer(player_t *player)
|
||||||
LUA_InvalidateUserdata(player);
|
LUA_InvalidateUserdata(player);
|
||||||
LUA_InvalidateUserdata(player->karthud);
|
LUA_InvalidateUserdata(player->karthud);
|
||||||
LUA_InvalidateUserdata(&player->cmd);
|
LUA_InvalidateUserdata(&player->cmd);
|
||||||
|
LUA_InvalidateUserdata(&player->itemRoulette.itemList);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||||
|
|
||||||
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
||||||
WRITEUINT8(save->p, (UINT8)players[i].botvars.rival);
|
WRITEUINT8(save->p, (UINT8)players[i].botvars.rival);
|
||||||
|
WRITEUINT8(save->p, (UINT8)players[i].botvars.foe);
|
||||||
|
|
||||||
WRITEUINT32(save->p, players[i].score);
|
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].difficulty = READUINT8(save->p);
|
||||||
savedata.bots[pid].rival = (boolean)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);
|
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.difficulty);
|
||||||
WRITEUINT8(save->p, players[i].botvars.diffincrease);
|
WRITEUINT8(save->p, players[i].botvars.diffincrease);
|
||||||
WRITEUINT8(save->p, players[i].botvars.rival);
|
WRITEUINT8(save->p, players[i].botvars.rival);
|
||||||
|
WRITEUINT8(save->p, players[i].botvars.foe);
|
||||||
WRITEFIXED(save->p, players[i].botvars.rubberband);
|
WRITEFIXED(save->p, players[i].botvars.rubberband);
|
||||||
WRITEUINT8(save->p, players[i].botvars.bumpslow);
|
WRITEUINT8(save->p, players[i].botvars.bumpslow);
|
||||||
WRITEUINT32(save->p, players[i].botvars.itemdelay);
|
WRITEUINT32(save->p, players[i].botvars.itemdelay);
|
||||||
|
|
@ -782,33 +785,33 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
||||||
WRITEUINT8(save->p, players[i].itemRoulette.active);
|
WRITEUINT8(save->p, players[i].itemRoulette.active);
|
||||||
|
|
||||||
#ifdef ITEM_LIST_SIZE
|
#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++)
|
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);
|
WRITESINT8(save->p, KITEM_NONE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WRITESINT8(save->p, players[i].itemRoulette.itemList[q]);
|
WRITESINT8(save->p, players[i].itemRoulette.itemList.items[q]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (players[i].itemRoulette.itemList == NULL)
|
if (players[i].itemRoulette.itemList.items == NULL)
|
||||||
{
|
{
|
||||||
WRITEUINT32(save->p, 0);
|
WRITEUINT32(save->p, 0);
|
||||||
WRITEUINT32(save->p, 0);
|
WRITEUINT32(save->p, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WRITEUINT32(save->p, players[i].itemRoulette.itemListCap);
|
WRITEUINT32(save->p, players[i].itemRoulette.itemList.cap);
|
||||||
WRITEUINT32(save->p, players[i].itemRoulette.itemListLen);
|
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
|
#endif
|
||||||
|
|
@ -1430,6 +1433,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
||||||
players[i].botvars.difficulty = READUINT8(save->p);
|
players[i].botvars.difficulty = READUINT8(save->p);
|
||||||
players[i].botvars.diffincrease = READUINT8(save->p);
|
players[i].botvars.diffincrease = READUINT8(save->p);
|
||||||
players[i].botvars.rival = (boolean)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.rubberband = READFIXED(save->p);
|
||||||
players[i].botvars.bumpslow = READUINT8(save->p);
|
players[i].botvars.bumpslow = READUINT8(save->p);
|
||||||
players[i].botvars.itemdelay = READUINT32(save->p);
|
players[i].botvars.itemdelay = READUINT32(save->p);
|
||||||
|
|
@ -1447,44 +1451,44 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
||||||
players[i].itemRoulette.active = (boolean)READUINT8(save->p);
|
players[i].itemRoulette.active = (boolean)READUINT8(save->p);
|
||||||
|
|
||||||
#ifdef ITEM_LIST_SIZE
|
#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++)
|
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
|
#else
|
||||||
players[i].itemRoulette.itemListCap = (size_t)READUINT32(save->p);
|
players[i].itemRoulette.itemList.cap = (size_t)READUINT32(save->p);
|
||||||
players[i].itemRoulette.itemListLen = (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(
|
players[i].itemRoulette.itemList.items = (SINT8*)Z_Calloc(
|
||||||
sizeof(SINT8) * players[i].itemRoulette.itemListCap,
|
sizeof(SINT8) * players[i].itemRoulette.itemList.cap,
|
||||||
PU_STATIC,
|
PU_STATIC,
|
||||||
&players[i].itemRoulette.itemList
|
NULL
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
players[i].itemRoulette.itemList = Z_Realloc(
|
players[i].itemRoulette.itemList.items = (SINT8*)Z_Realloc(
|
||||||
players[i].itemRoulette.itemList,
|
players[i].itemRoulette.itemList.items,
|
||||||
sizeof(SINT8) * players[i].itemRoulette.itemListCap,
|
sizeof(SINT8) * players[i].itemRoulette.itemList.cap,
|
||||||
PU_STATIC,
|
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");
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ struct savedata_bot_s
|
||||||
UINT8 skin;
|
UINT8 skin;
|
||||||
UINT8 difficulty;
|
UINT8 difficulty;
|
||||||
boolean rival;
|
boolean rival;
|
||||||
|
boolean foe;
|
||||||
UINT32 score;
|
UINT32 score;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue