diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 603239ac4..d4e256c7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3ceb00a64..9e7914e1e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index c569726cd..45de60434 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -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; diff --git a/src/k_itemlist.cpp b/src/k_itemlist.cpp new file mode 100644 index 000000000..5cec443c9 --- /dev/null +++ b/src/k_itemlist.cpp @@ -0,0 +1,61 @@ +#include + +#include "d_player.h" +#include "doomdef.h" +#include "k_items.h" +#include "v_video.h" + +extern "C" +{ + std::unordered_map 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 +} diff --git a/src/k_itemlist.hpp b/src/k_itemlist.hpp new file mode 100644 index 000000000..7f33a57c2 --- /dev/null +++ b/src/k_itemlist.hpp @@ -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 \ No newline at end of file diff --git a/src/k_items.c b/src/k_items.c index 2e2416178..5d15d8c1f 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -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) diff --git a/src/p_setup.c b/src/p_setup.c index 777008647..90674eed6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -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; diff --git a/src/y_inter.c b/src/y_inter.c index 458650138..851d30819 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -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) / (8 * vid.dupx); + else if (count == 8) + goto skiptallydrawer; + else if (count < 16) + x += (((((16 - count)<>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)<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)<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; }