Start work on an item roll tracker

Uses an unordered-map system so we don't loop through every item constantly

Opting for trying to fit everyone on the screen; 320x200 users can deal with it
Scrolling is not yet implemented, and this system isn't netsynched yet
This commit is contained in:
yamamama 2025-12-06 04:13:19 -05:00
parent 1b91f96fa0
commit 327035e68e
8 changed files with 174 additions and 19 deletions

View file

@ -139,6 +139,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
k_botsearch.cpp
k_cluster.cpp
k_items.c
k_itemlist.cpp
k_grandprix.c
k_boss.c
k_hud.c

View file

@ -69,6 +69,7 @@
#include "g_party.h"
#include "k_specialstage.h"
#include "k_items.h"
#include "k_itemlist.hpp"
#define CV_RESTRICT CV_NETVAR
@ -605,6 +606,8 @@ consvar_t cv_kartlegacyspbdist = CVAR_INIT ("kartlegacyspbdist", "2216", CV_NETV
// SPB Rush toggle; toggles on/off the more aggressive "pressure" odds when an SPB is active
consvar_t cv_kartspbrush = CVAR_INIT ("kartspbrush", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_itemlist = CVAR_INIT ("kartitemlist", "On", CV_NETVAR, CV_OnOff, NULL);
// Time limit for Alt. Shrink
static CV_PossibleValue_t altshrinktime_cons_t[] = {{0, "MIN"}, {(INT16_MAX / TICRATE), "MAX"}, {0, NULL}};
consvar_t cv_kartaltshrinktime = CVAR_INIT ("kartaltshrinktime", "14", CV_NETVAR|CV_CHEAT|CV_GUARD, altshrinktime_cons_t, NULL);
@ -1075,6 +1078,8 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_dummyconsvar);
CV_RegisterVar(&cv_encorevotes);
CV_RegisterVar(&cv_itemlist);
#ifdef USE_STUN
CV_RegisterVar(&cv_stunserver);
#endif
@ -6527,6 +6532,8 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum)
}
else
{
K_AddItemRollToList((INT32)(player - players), item, amt);
CV_CheaterWarning(playernum, va("give item %s x%d", DEH_KartItemName(item), amt));
}
break;

View file

@ -221,6 +221,8 @@ extern consvar_t cv_kartlegacyspbdist;
extern consvar_t cv_kartspbrush;
extern consvar_t cv_itemlist;
extern consvar_t cv_encorevotes;
extern consvar_t cv_votetime;

61
src/k_itemlist.cpp Normal file
View file

@ -0,0 +1,61 @@
#include <unordered_map>
#include "d_player.h"
#include "doomdef.h"
#include "k_items.h"
#include "v_video.h"
extern "C"
{
std::unordered_map<kartitemtype_e, INT32> itemcounter[MAXPLAYERS];
void K_ClearItemRollLists(void)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
itemcounter[i].clear();
}
}
void K_AddItemRollToList(INT32 pid, kartitemtype_e item, INT32 amount)
{
if (auto search = itemcounter[pid].find(item); search != itemcounter[pid].end())
itemcounter[pid][item] += amount;
else
itemcounter[pid][item] = amount; // If this roll didn't exist before, it does now :^)
}
#define ITEMLOG_SPACE 1
// Draws an item in the player's item list. Draws nothing if the list is empty.
void K_DrawItemList(INT32 pid, fixed_t x, fixed_t y)
{
if (itemcounter[pid].size() < 1)
return;
patch_t* localpatch;
fixed_t dx = x;
INT32 ir_length;
for (const auto& n : itemcounter[pid])
{
if (n.second < 1)
continue;
localpatch = K_GetCachedItemPatch(n.first, true, 0);
ir_length = (INT32)strlen(va("%d", n.second));
V_DrawFixedPatch(dx, y - (25 * FRACUNIT / 6), FRACUNIT / 3, 0, localpatch, NULL);
V_DrawSmallString((dx / FRACUNIT) + ((5 + (std::max(0, ir_length - 1) * 3))),
(y / FRACUNIT) + 2,
V_ALLOWLOWERCASE | V_6WIDTHSPACE,
va("%d", n.second));
dx += (6 + std::max(0, (ir_length * 3) - 3) + ITEMLOG_SPACE) * FRACUNIT;
}
}
#undef ITEMLOG_SPACE
}

15
src/k_itemlist.hpp Normal file
View file

@ -0,0 +1,15 @@
#include "doomdef.h"
#include "k_items.h"
#ifdef __cplusplus
extern "C"
{
#endif
void K_ClearItemRollLists(void);
void K_AddItemRollToList(INT32 pid, kartitemtype_e item, INT32 amount);
void K_DrawItemList(INT32 pid, fixed_t x, fixed_t y);
#ifdef __cplusplus
}
#endif

View file

@ -38,6 +38,7 @@
#include "k_waypoint.h"
#include "k_director.h"
#include "k_cluster.hpp"
#include "k_itemlist.hpp"
#include "k_items.h"
#include "k_collide.h"
@ -379,6 +380,8 @@ void K_AwardPlayerItem(player_t *player, kartitemtype_e type, UINT8 amount, kart
amount *= 2;
player->itemamount = amount;
K_AddItemRollToList((INT32)(player - players), type, amount);
}
static void K_AwardPlayerResult(player_t *player, kartresult_t *result, kartitemblink_e blink)

View file

@ -108,6 +108,7 @@
#include "k_mapuser.h"
#include "p_deepcopy.h"
#include "k_specialstage.h"
#include "k_itemlist.hpp"
#include "g_input.h"
#include "blan/b_soc.h"
@ -8217,6 +8218,8 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
antibumptime = (tic_t)cv_kartantibump.value * TICRATE;
K_ClearItemRollLists();
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;

View file

@ -49,6 +49,7 @@
#include "k_grandprix.h"
#include "k_bot.h" // cv_botcanvote
#include "r_fps.h" // R_GetTimeFrac
#include "k_itemlist.hpp"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -80,9 +81,23 @@ typedef struct
UINT8 pos[MAXPLAYERS]; // player positions. used for ties
boolean rankingsmode; // rankings mode
boolean itemrolls;
boolean encore; // encore mode
} y_data;
static boolean Y_ItemListActive(void)
{
UINT8 i = 0, nump = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
nump++;
}
return ((cv_itemlist.value != 0) && (nump > 1));
}
static y_data data;
// graphics
@ -99,6 +114,7 @@ static UINT8 *y_screenbuffer;
static INT32 intertic;
static INT32 endtic = -1;
static INT32 sorttic = -1;
static INT32 rolltic = -1;
intertype_t intertype = int_none;
intertype_t intermissiontypes[NUMGAMETYPES];
@ -253,6 +269,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
data.levelstring[sizeof data.levelstring - 1] = '\0';
data.encore = encoremode;
data.itemrolls = Y_ItemListActive();
memset(data.jitter, 0, sizeof (data.jitter));
}
@ -382,6 +399,7 @@ void Y_CleanupScreenBuffer(void)
void Y_IntermissionDrawer(void)
{
INT32 i, whiteplayer = MAXPLAYERS, x = 4, hilicol = V_YELLOWMAP; // fallback
INT32 xx = x;
if (intertype == int_none || rendermode == render_none)
return;
@ -435,7 +453,18 @@ void Y_IntermissionDrawer(void)
hilicol = V_YELLOWMAP;
}
if (sorttic != -1 && intertic > sorttic)
if (rolltic != -1 && intertic > (rolltic - 8) && (intertic < (rolltic + 8)))
{
INT32 count = (intertic - (rolltic - 8));
if (count < 8)
x -= ((((count<<FRACBITS) + R_GetTimeFrac(RTF_INTER)) * vid.width)>>FRACBITS) / (8 * vid.dupx);
else if (count == 8)
goto skiptallydrawer;
else if (count < 16)
x += (((((16 - count)<<FRACBITS) - R_GetTimeFrac(RTF_INTER)) * vid.width)>>FRACBITS) / (8 * vid.dupx);
}
else if (sorttic != -1 && intertic > sorttic)
{
INT32 count = (intertic - sorttic);
@ -456,6 +485,10 @@ void Y_IntermissionDrawer(void)
boolean manyplayers16 = (data.numplayers > NUMFORNEWCOLUMN*2);
boolean manyplayers8 = (data.numplayers > NUMFORNEWCOLUMN);
boolean displayitemrolls = (data.itemrolls && (intertic <= rolltic));
if (displayitemrolls)
manyplayers16 = manyplayers8 = false;
int y2;
@ -510,13 +543,6 @@ void Y_IntermissionDrawer(void)
V_DrawRightAlignedString(x+152, 24, hilicol, timeheader);
}
else
{
V_DrawCenteredString(x+6, 24, hilicol, "#");
V_DrawString(x+36, 24, hilicol, "NAME");
V_DrawRightAlignedString(x+(BASEVIDWIDTH/2)+152, 24, hilicol, timeheader);
}
for (i = 0; i < data.numplayers; i++)
{
@ -530,36 +556,52 @@ void Y_IntermissionDrawer(void)
if (dojitter)
y--;
if (manyplayers16)
V_DrawPingNum(x+6, y+2, 0, data.pos[i], NULL);
if (manyplayers16||displayitemrolls)
V_DrawPingNum(x + 6, (displayitemrolls) ? y-2 : y+2, 0, data.pos[i], NULL);
else
V_DrawCenteredString(x+6, y, 0, va("%d", data.pos[i]));
if (data.color[i])
{
UINT8 *colormap = R_GetTranslationColormap(*data.character[i], *data.color[i], GTC_CACHE);
patch_t *facerank = faceprefix[*data.character[i]][FACE_RANK];
patch_t *facerank;
if (displayitemrolls)
facerank = faceprefix[*data.character[i]][FACE_MINIMAP];
else
facerank = faceprefix[*data.character[i]][FACE_RANK];
fixed_t scale = FRACUNIT;
if (manyplayers16)
{
// fixed_t scale = K_UseHighResPortraits() ? FRACUNIT/4 : FRACUNIT/2;
fixed_t scale = FRACUNIT/2;
scale = FRACUNIT / 2;
V_DrawFixedPatch((x+8)<<FRACBITS, (y+1)<<FRACBITS, scale, 0, facerank, colormap);
}
else
{
V_DrawMappedPatch(x+16+facerank->leftoffset, y-4+facerank->topoffset, 0, facerank, colormap);
INT32 xoffs, yoffs;
scale = (displayitemrolls) ? FRACUNIT/2 : FRACUNIT;
xoffs = FixedMul(16, scale);
yoffs = FixedMul(4, scale);
V_DrawFixedPatch((x+xoffs)<<FRACBITS, (y-yoffs)<<FRACBITS, scale, 0, facerank, colormap);
xx = (x+xoffs) + FixedMul(20, scale);
}
}
if (data.num[i] == whiteplayer && data.numplayers <= NUMFORNEWCOLUMN*2)
if ((!displayitemrolls) && data.num[i] == whiteplayer && data.numplayers <= NUMFORNEWCOLUMN*2)
{
UINT8 cursorframe = (intertic / 4) % 8;
patch_t *highlight = W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE);
V_DrawScaledPatch(x+16+highlight->leftoffset, y-4+highlight->topoffset, 0, highlight);
}
if ((players[data.num[i]].pflags & PF_NOCONTEST) && players[data.num[i]].bot)
if ((!displayitemrolls) && (players[data.num[i]].pflags & PF_NOCONTEST) && players[data.num[i]].bot)
{
// RETIRED!!
patch_t *retire = W_CachePatchName("K_NOBLNS", PU_CACHE);
@ -578,10 +620,20 @@ void Y_IntermissionDrawer(void)
y2 = y;
INT32 slen = 0;
if (manyplayers16)
V_DrawThinString(x+18, y, hilicol|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
else if (displayitemrolls)
{
V_DrawSmallString(xx, y2 + 1, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
slen = V_SmallStringWidth(strtime, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE);
}
else if (manyplayers8)
V_DrawThinString(x+36, y2-1, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
{
V_DrawThinString(xx, y2 - 1, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
slen = V_ThinStringWidth(strtime, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE);
}
else
V_DrawString(x+36, y2, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime);
@ -622,6 +674,10 @@ void Y_IntermissionDrawer(void)
else
V_DrawRightAlignedString(x+152+gutter, y, 0, strtime);
}
else if (data.itemrolls && (intertic <= rolltic))
{
K_DrawItemList((INT32)(&players[data.num[i]] - players), (xx+2+slen) * FRACUNIT, (y-1) * FRACUNIT);
}
else
{
if (data.val[i] == (UINT32_MAX-1))
@ -671,9 +727,9 @@ void Y_IntermissionDrawer(void)
}
else
{
y += 18;
y += (displayitemrolls) ? 8 : 18;
if (i == NUMFORNEWCOLUMN-1)
if ((!displayitemrolls) && i == NUMFORNEWCOLUMN-1)
{
y = 41;
x += BASEVIDWIDTH/2;
@ -991,6 +1047,13 @@ void Y_StartIntermission(void)
{
// Calculate who won
Y_CalculateMatchData(0, Y_CompareTime);
if (data.itemrolls)
{
rolltic = 15 * TICRATE;
sorttic += rolltic;
timer += rolltic;
}
break;
}