Merge pull request 'Item roll tracker' (#198) from itemlists into next

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/198
This commit is contained in:
yamamama 2025-12-13 03:45:42 +01:00
commit cf3c123187
15 changed files with 542 additions and 25 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
@ -174,6 +175,7 @@ static void KartItemPush_OnChange(void);
static void KartAntiBump_OnChange(void);
static void KartItemBreaker_OnChange(void);
static void KartBumpSpark_OnChange(void);
static void KartItemList_OnChange(void);
static void Schedule_OnChange(void);
@ -605,6 +607,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_CALL|CV_NOINIT, CV_OnOff, KartItemList_OnChange);
// 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 +1079,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 +6533,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;
@ -8350,6 +8358,39 @@ static void KartBumpSpark_OnChange(void)
}
}
static void KartItemList_OnChange(void)
{
if (K_CanChangeRules(false) == false)
{
return;
}
if (!K_ItemListActive() && cv_itemlist.value)
{
if (leveltime < starttime)
{
itemlistactive = true;
CONS_Printf(M_GetText("Item rolls will be displayed.\n"));
}
else
{
CONS_Printf(M_GetText("Item rolls will be displayed next round.\n"));
}
}
else if (K_ItemListActive() && !cv_itemlist.value)
{
if (leveltime < starttime)
{
itemlistactive = false;
CONS_Printf(M_GetText("Item rolls will not be displayed.\n"));
}
else
{
CONS_Printf(M_GetText("Item rolls will not be displayed next round.\n"));
}
}
}
static void Schedule_OnChange(void)
{
size_t i;

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;

View file

@ -136,7 +136,7 @@ static patch_t *kp_racefinish[6];
static patch_t *kp_positionnum[NUMPOSNUMS][NUMPOSFRAMES];
static patch_t *kp_winnernum[NUMPOSFRAMES];
static patch_t *kp_facenum[MAXPLAYERS+1];
patch_t *kp_facenum[MAXPLAYERS+1];
static patch_t *kp_facehighlight[8];
static patch_t *kp_nocontestminimap;

View file

@ -66,6 +66,8 @@ extern consvar_t cv_colorizedhudcolor;
extern consvar_t cv_newtabranking;
extern patch_t *kp_facenum[MAXPLAYERS+1];
struct trackingResult_t
{
fixed_t x, y;

151
src/k_itemlist.cpp Normal file
View file

@ -0,0 +1,151 @@
#include <unordered_map>
#include "byteptr.h"
#include "d_player.h"
#include "doomdef.h"
#include "k_items.h"
#include "p_saveg.h"
#include "v_video.h"
extern "C"
{
std::unordered_map<kartitemtype_e, INT32> itemcounter[MAXPLAYERS];
//
// Clears out all item lists for all players. Should only run during race setup.
//
void K_ClearItemRollLists(void)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
itemcounter[i].clear();
}
}
//
// Adds an item roll to the item roll list.
// If an entry for the item already exists, this function adds to its roll count.
//
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 :^)
}
//
// Gets the size of the item roll list. Primarily used for syncing netgames.
//
UINT32 K_GetItemListSize(INT32 pid)
{
return static_cast<UINT32>(itemcounter[pid].size());
}
//
// Sets an entry in the item roll list to a specific value.
//
void K_SetItemListEntry(INT32 pid, kartitemtype_e item, INT32 num)
{
itemcounter[pid][item] = num;
}
//
// Gets the value of an entry in the item roll list, given it exists.
// If nothing is found, this value returns 0.
//
UINT32 K_GetItemListEntry(INT32 pid, kartitemtype_e item)
{
if (auto search = itemcounter[pid].find(item); search != itemcounter[pid].end())
{
return itemcounter[pid][item];
}
return 0;
}
//
// C and C++ are like oil and water at points; we need to synch every entry in the unordered
// map by doing... this.
//
UINT32 K_SyncItemList(savebuffer_t* save, INT32 pid)
{
UINT32 buffer_size;
if (save->write)
{
// Buffer size = list size * 2 (2 entries for each buffer element)
buffer_size = static_cast<UINT32>(itemcounter[pid].size());
// First, write the size of the buffer we're about to send over.
WRITEUINT32(save->p, buffer_size);
// Then, comb through the map and write every entry in it to the save buffer.
for (const auto& n : itemcounter[pid])
{
WRITEUINT32(save->p, static_cast<UINT32>(n.first));
WRITEUINT32(save->p, static_cast<UINT32>(n.second));
}
return buffer_size;
}
else
{
// Get the buffer size.
buffer_size = READUINT32(save->p);
UINT32 i, item, amt;
for (i = 0; i < buffer_size; i++)
{
// Loop through the save buffer and write everything we find into the given item
// list.
item = READUINT32(save->p);
amt = READUINT32(save->p);
itemcounter[pid][static_cast<kartitemtype_e>(item)] = amt;
}
return buffer_size;
}
return 0;
}
#define ITEMLOG_SPACE 1
// Draws an item in the player's item list. Draws nothing if the list is empty.
fixed_t K_DrawItemList(INT32 pid, fixed_t x, fixed_t y)
{
if (itemcounter[pid].size() < 1)
return 0;
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 = static_cast<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;
}
// Return the overall "width" of the list.
return dx - x;
}
#undef ITEMLOG_SPACE
}

24
src/k_itemlist.hpp Normal file
View file

@ -0,0 +1,24 @@
#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);
fixed_t K_DrawItemList(INT32 pid, fixed_t x, fixed_t y);
UINT32 K_GetItemListSize(INT32 pid);
// Getter and setter
void K_SetItemListEntry(INT32 pid, kartitemtype_e item, INT32 num);
UINT32 K_GetItemListEntry(INT32 pid, kartitemtype_e item);
// Netsynch; returns the size of the list buffer, always.
UINT32 K_SyncItemList(savebuffer_t *save, INT32 pid);
#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,9 @@ void K_AwardPlayerItem(player_t *player, kartitemtype_e type, UINT8 amount, kart
amount *= 2;
player->itemamount = amount;
if (itemlistactive)
K_AddItemRollToList((INT32)(player - players), type, amount);
}
static void K_AwardPlayerResult(player_t *player, kartresult_t *result, kartitemblink_e blink)

View file

@ -10972,6 +10972,17 @@ boolean K_ItemLitterActive(void)
return false;
}
boolean K_ItemListActive(void)
{
if (itemlistactive)
{
// Item listing is enabled!
return true;
}
return false;
}
boolean K_ItemPushingActive(void)
{
return itempushing;

View file

@ -357,6 +357,7 @@ boolean K_DraftingActive(void);
boolean K_AirDropActive(void);
boolean K_AirThrustActive(void);
boolean K_ItemLitterActive(void);
boolean K_ItemListActive(void);
boolean K_ItemPushingActive(void);
INT32 K_GetBumpSpark(void);
boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound);

View file

@ -34,6 +34,7 @@
#include "k_hud.h"
#include "k_waypoint.h"
#include "k_items.h"
#include "k_itemlist.hpp"
#include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff
#include "p_spec.h" // P_StartQuake
@ -4364,6 +4365,12 @@ static int lib_kItemLitterActive(lua_State *L)
return 1;
}
static int lib_kItemListActive(lua_State *L)
{
lua_pushboolean(L, K_ItemListActive());
return 1;
}
// Gets the currently active bumpspark type.
static int lib_kGetBumpSpark(lua_State *L)
{
@ -5244,6 +5251,75 @@ static int lib_kSetPlayerItemCooldown(lua_State *L)
return 0;
}
static int lib_kAddItemRollToList(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
kartitemtype_e item_id = (kartitemtype_e)luaL_checkinteger(L, 2);
INT32 amt = luaL_checkinteger(L, 3);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (item_id < 1 || item_id >= numkartitems)
return luaL_error(L, "item number %d out of range (1 - %d)", item_id, numkartitems-1);
INT32 pid = (INT32)(player - players);
K_AddItemRollToList(pid, item_id, amt);
return 0;
}
static int lib_kGetItemListSize(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
INT32 pid = (INT32)(player - players);
lua_pushinteger(L, K_GetItemListSize(pid));
return 1;
}
static int lib_kSetItemListEntry(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
kartitemtype_e item_id = (kartitemtype_e)luaL_checkinteger(L, 2);
INT32 num = luaL_checkinteger(L, 3);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (item_id < 1 || item_id >= numkartitems)
return luaL_error(L, "item number %d out of range (1 - %d)", item_id, numkartitems-1);
INT32 pid = (INT32)(player - players);
K_SetItemListEntry(pid, item_id, num);
return 0;
}
static int lib_kGetItemListEntry(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
kartitemtype_e item_id = (kartitemtype_e)luaL_checkinteger(L, 2);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (item_id < 1 || item_id >= numkartitems)
return luaL_error(L, "item number %d out of range (1 - %d)", item_id, numkartitems-1);
INT32 pid = (INT32)(player - players);
lua_pushinteger(L, K_GetItemListEntry(pid, item_id));
return 1;
}
// G_INPUT
////////////
@ -5618,6 +5694,7 @@ static luaL_Reg lib[] = {
{"K_DraftingActive",lib_kDraftingActive},
{"K_AirDropActive",lib_kAirDropActive},
{"K_ItemLitterActive",lib_kItemLitterActive},
{"K_ItemListActive", lib_kItemListActive},
{"K_GetBumpSpark",lib_kGetBumpSpark},
{"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints},
{"K_DoBoost",lib_kDoBoost},
@ -5706,6 +5783,12 @@ static luaL_Reg lib[] = {
// k_items
{"K_SetPlayerItemCooldown", lib_kSetPlayerItemCooldown},
// k_itemlist
{"K_AddItemRollToList", lib_kAddItemRollToList},
{"K_GetItemListSize", lib_kGetItemListSize},
{"K_SetItemListEntry", lib_kSetItemListEntry},
{"K_GetItemListEntry", lib_kGetItemListEntry},
//g_input
{"G_SetPlayerGamepadIndicatorColor",lib_gSetPlayerGamepadIndicatorColor},
{"G_PlayerDeviceRumble",lib_gPlayerDeviceRumble},

View file

@ -622,6 +622,7 @@ extern boolean airthrustactive;
extern boolean itemlittering;
extern boolean itempushing;
extern UINT8 bumpsparkactive;
extern boolean itemlistactive;
extern UINT16 bossdisabled;
extern boolean stoppedclock;

View file

@ -45,6 +45,7 @@
#include "acs/interface.h"
#include "g_party.h"
#include "k_waypoint.h"
#include "k_itemlist.hpp"
#include <tracy/tracy/TracyC.h>
@ -404,6 +405,9 @@ static void P_RelinkWaypoint(savebuffer_t *save, waypoint_t **ptr)
#define ARCHIVEBLOCK_SPECIALS 0x7F228378
#define ARCHIVEBLOCK_WAYPOINTS 0x7F46498F
// Specialized netsynch markers
#define PLYRSYNC_ITEMLIST (1)
static inline void P_ArchivePlayer(savebuffer_t *save)
{
const player_t *player = &players[consoleplayer];
@ -457,6 +461,12 @@ static void P_NetSyncPlayers(savebuffer_t *save)
SYNC(playerconsole[i]);
SYNC(splitscreen_invitations[i]);
// Item lists
if (P_SyncUINT32(save, (K_GetItemListSize(i) ? PLYRSYNC_ITEMLIST : 0)))
{
K_SyncItemList(save, i);
}
SYNC(players[i].angleturn);
SYNC(players[i].aiming);
SYNC(players[i].drawangle);
@ -4222,6 +4232,7 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending)
SYNCBOOLEAN(airdropactive);
SYNCBOOLEAN(itemlittering);
SYNCBOOLEAN(itempushing);
SYNCBOOLEAN(itemlistactive);
SYNC(bumpsparkactive);
SYNC(antibumptime);

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"
@ -164,6 +165,7 @@ boolean airthrustactive;
boolean itemlittering;
boolean itempushing;
UINT8 bumpsparkactive;
boolean itemlistactive;
UINT16 bossdisabled;
boolean stoppedclock;
boolean levelloading;
@ -8177,6 +8179,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
airthrustactive = false;
itemlittering = false;
itempushing = false;
itemlistactive = false;
bumpsparkactive = 0;
antibumptime = 0;
@ -8213,10 +8216,15 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
if (cv_kartitempush.value)
itempushing = true;
if (cv_itemlist.value)
itemlistactive = true;
bumpsparkactive = (UINT8)cv_kartbumpspark.value;
antibumptime = (tic_t)cv_kartantibump.value * TICRATE;
K_ClearItemRollLists();
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;

View file

@ -49,11 +49,18 @@
#include "k_grandprix.h"
#include "k_bot.h" // cv_botcanvote
#include "r_fps.h" // R_GetTimeFrac
#include "k_hud.h"
#include "k_itemlist.hpp"
#ifdef HWRENDER
#include "hardware/hw_main.h"
#endif
#define ITEMLIST_PLAYER_YOFFSET 9
#define ITEMLIST_SCROLLSPEED (3 * FRACUNIT / 4)
#define ITEMLIST_SCROLLDELAY (3 * TICRATE)
#define ITEMLIST_SCROLLREPEAT 1
typedef struct
{
char patch[9];
@ -80,9 +87,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 ((itemlistactive) && (nump > 1));
}
static y_data data;
// graphics
@ -99,6 +120,12 @@ static UINT8 *y_screenbuffer;
static INT32 intertic;
static INT32 endtic = -1;
static INT32 sorttic = -1;
static INT32 rolltic = -1;
static fixed_t listscroll_length = 0;
static boolean listscroll_reverse = false;
static INT32 listscroll_delay = 0;
static fixed_t xscroll = 0;
intertype_t intertype = int_none;
intertype_t intermissiontypes[NUMGAMETYPES];
@ -253,6 +280,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,10 +410,17 @@ void Y_CleanupScreenBuffer(void)
void Y_IntermissionDrawer(void)
{
INT32 i, whiteplayer = MAXPLAYERS, x = 4, hilicol = V_YELLOWMAP; // fallback
INT32 xx = x, x_base = x;
if (intertype == int_none || rendermode == render_none)
return;
INT32 w = (vid.width / vid.dupx);
INT32 h = (vid.height / vid.dupy);
const INT32 vidxdiff = (w - BASEVIDWIDTH) / 2;
const INT32 vidydiff = (h - BASEVIDHEIGHT) / 2;
if (!useinterpic && y_screenbuffer == NULL
#ifdef HWRENDER
// TODO resolution changes breaks the screentexture capture, I have no clue why
@ -435,7 +470,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);
@ -452,10 +498,15 @@ void Y_IntermissionDrawer(void)
#define NUMFORNEWCOLUMN 8
INT32 y = 41, gutter = ((data.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2));
INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2;
fixed_t newlist_xpush = (BASEVIDWIDTH/2) * FRACUNIT;
const char *timeheader;
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 +561,8 @@ 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);
}
INT32 xscroll_px = (xscroll / FRACUNIT);
for (i = 0; i < data.numplayers; i++)
{
@ -530,36 +576,78 @@ void Y_IntermissionDrawer(void)
if (dojitter)
y--;
if (manyplayers16)
V_DrawPingNum(x+6, y+2, 0, data.pos[i], NULL);
if (displayitemrolls)
{
if (data.pos[i] < 0 || data.pos[i] > 16)
V_DrawPingNum(x+2-xscroll_px, y+1, 0, data.pos[i], NULL);
else
V_DrawScaledPatch(x-5-xscroll_px, y+1, 0, kp_facenum[data.pos[i]]);
}
else if (manyplayers16)
{
V_DrawPingNum(x + 6, 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;
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);
if (displayitemrolls)
{
V_DrawFixedPatch(
((x+11-xscroll_px)*FRACUNIT) + ((facerank->leftoffset) * scale),
((y+1)*FRACUNIT) + ((facerank->topoffset) * scale),
scale,
0,
facerank,
colormap
);
if ((x_base - x) == 0)
{
// Terrible hack to remedy offset woes: Set a "base" value for x to reference.
x_base = (x+11) + 20;
}
xx = x + x_base - 4;
}
else
{
V_DrawFixedPatch((x+xoffs)<<FRACBITS, ((y-yoffs)<<FRACBITS), scale, 0, facerank, colormap);
}
}
}
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 +666,32 @@ void Y_IntermissionDrawer(void)
y2 = y;
INT32 slen = 0;
INT32 slen_temp = slen;
if (manyplayers16)
V_DrawThinString(x+18, y, hilicol|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
V_DrawThinString(x+18, y, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
else if (displayitemrolls)
{
V_DrawThinString(x + 20 - xscroll_px, y, ((data.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
// Get the longest string size. This is... gross.
INT32 ii;
for (ii = 0; ii < data.numplayers; ii++)
{
if (data.num[ii] != MAXPLAYERS && playeringame[data.num[ii]] && !players[data.num[ii]].spectator)
{
slen_temp = V_ThinStringWidth(data.name[ii], ((data.num[ii] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE);
slen = ((slen_temp > slen) ? slen_temp : slen);
}
}
}
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 +732,11 @@ void Y_IntermissionDrawer(void)
else
V_DrawRightAlignedString(x+152+gutter, y, 0, strtime);
}
else if (data.itemrolls && (intertic <= rolltic))
{
const fixed_t itemlistlen = K_DrawItemList((INT32)(data.num[i]), ((xx+2+slen-xscroll_px) * FRACUNIT), ((y+1) * FRACUNIT));
newlist_xpush = max(newlist_xpush, ((x_base+9+slen) * FRACUNIT) + itemlistlen);
}
else
{
if (data.val[i] == (UINT32_MAX-1))
@ -671,17 +786,20 @@ void Y_IntermissionDrawer(void)
}
else
{
y += 18;
y += (displayitemrolls) ? ITEMLIST_PLAYER_YOFFSET : 18;
if (i == NUMFORNEWCOLUMN-1)
if ((i % 16) == (((displayitemrolls) ? 2 : 1) * NUMFORNEWCOLUMN) - 1)
{
y = 41;
x += BASEVIDWIDTH/2;
x += (newlist_xpush / FRACUNIT);
newlist_xpush = (BASEVIDWIDTH / 2) * FRACUNIT;
}
}
#undef NUMFORNEWCOLUMN
}
listscroll_length = max(0, x - BASEVIDWIDTH) * FRACUNIT;
}
skiptallydrawer:
@ -762,6 +880,53 @@ void Y_Ticker(void)
intertic++;
if (listscroll_length && (intertic > (TICRATE * 2)) && (intertic <= rolltic))
{
if (!listscroll_reverse)
{
if ((xscroll >= listscroll_length))
{
if (!listscroll_delay)
listscroll_delay = ITEMLIST_SCROLLDELAY;
}
else
xscroll = min(listscroll_length, xscroll + ITEMLIST_SCROLLSPEED);
}
else
{
if ((xscroll <= 0))
{
if (!listscroll_delay)
listscroll_delay = ITEMLIST_SCROLLDELAY;
}
else
xscroll = max(0, xscroll - ITEMLIST_SCROLLSPEED);
}
if (listscroll_delay)
{
listscroll_delay--;
if (!listscroll_delay)
listscroll_reverse = (!listscroll_reverse);
}
}
else
{
listscroll_length = 0;
listscroll_delay = 0;
listscroll_reverse = false;
if (xscroll > 0)
{
if (intertic < rolltic)
xscroll = max(0, xscroll - ITEMLIST_SCROLLSPEED);
else
xscroll = 0;
}
}
// Team scramble code for team match and CTF.
// Don't do this if we're going to automatically scramble teams next round.
/*if (G_GametypeHasTeams() && cv_teamscramble.value && !cv_scrambleonchange.value && server)
@ -942,7 +1107,7 @@ void Y_StartIntermission(void)
if (!timer)
{
// Prevent a weird bug
timer = 1;
timer = 1;
}
else if (nump < 2 && !netgame)
{
@ -991,6 +1156,14 @@ void Y_StartIntermission(void)
{
// Calculate who won
Y_CalculateMatchData(0, Y_CompareTime);
if (data.itemrolls)
{
rolltic = (15 * TICRATE);
sorttic += rolltic;
timer += rolltic;
}
break;
}
@ -2152,3 +2325,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level)
g_pickedVote = pick;
timer = 0;
}
#undef ITEMLIST_PLAYER_YOFFSET
#undef ITEMLIST_SCROLLSPEED
#undef ITEMLIST_SCROLLDELAY