From efac1d27c2e74d5ef11b05d912e36c9376ecaad1 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 6 Nov 2025 22:57:21 +0100 Subject: [PATCH] Item refactor, part 1 Too much shit to explain, read the diff (you should anyway!) Very sloppy, expect lots of fixes TODO: SOC it all, separate "active odds" table, how to handle alt items --- src/Sourcefile | 3 +- src/command.h | 4 - src/d_netcmd.c | 132 +---- src/d_netcmd.h | 38 +- src/d_player.h | 55 -- src/deh_lua.c | 14 + src/deh_lua.h | 1 + src/deh_tables.c | 24 - src/doomstat.h | 3 - src/g_game.c | 8 +- src/info.c | 10 + src/k_altshrink.c | 82 --- src/k_altshrink.h | 60 --- src/k_bot.cpp | 1 + src/k_botitem.cpp | 4 +- src/k_botsearch.cpp | 1 + src/k_collide.c | 3 +- src/k_hud.c | 367 +++---------- src/k_hud.h | 2 +- src/{k_odds.c => k_items.c} | 1008 +++++++++++++++++++---------------- src/k_items.h | 147 +++++ src/k_kart.c | 83 +-- src/k_kart.h | 6 +- src/k_odds.h | 72 --- src/lua_baselib.c | 67 +-- src/lua_script.c | 11 +- src/m_menu.c | 133 ++--- src/p_enemy.c | 1 + src/p_inter.c | 4 +- src/p_mobj.c | 10 +- src/p_saveg.c | 11 +- src/p_setup.c | 12 +- src/p_spec.c | 2 +- src/p_tick.c | 10 +- src/p_user.c | 3 +- src/r_patchrotation.c | 1 + src/typedef.h | 5 + 37 files changed, 917 insertions(+), 1481 deletions(-) delete mode 100644 src/k_altshrink.c delete mode 100644 src/k_altshrink.h rename src/{k_odds.c => k_items.c} (56%) create mode 100644 src/k_items.h delete mode 100644 src/k_odds.h diff --git a/src/Sourcefile b/src/Sourcefile index 87fa585b3..311753777 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -133,8 +133,7 @@ k_bot.cpp k_botitem.cpp k_botsearch.cpp k_cluster.cpp -k_odds.c -k_altshrink.c +k_items.c k_grandprix.c k_boss.c k_hud.c diff --git a/src/command.h b/src/command.h index 5c0d81d8d..345be77df 100644 --- a/src/command.h +++ b/src/command.h @@ -189,10 +189,6 @@ extern CV_PossibleValue_t CV_Natural[]; #define KARTGP_NIGHTMARE 5 // Not a speed setting, gives expert speed with maxed out bots extern CV_PossibleValue_t kartspeed_cons_t[], gpdifficulty_cons_t[]; -// Alternative item types. -#define KARTITEM_NORMAL 0 -#define KARTITEM_ALTERN 1 - extern consvar_t cv_execversion; extern consvar_t cv_resetnetvars; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 20209ef7e..974e844d2 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -68,7 +68,7 @@ #include "m_perfstats.h" #include "g_party.h" #include "k_specialstage.h" -#include "k_altshrink.h" +#include "k_items.h" #define CV_RESTRICT CV_NETVAR @@ -167,9 +167,6 @@ static void KartItemLitter_OnChange(void); static void KartItemPush_OnChange(void); static void KartAntiBump_OnChange(void); static void KartItemBreaker_OnChange(void); -static void KartInvinType_OnChange(void); -static void KartEggmanType_OnChange(void); -static void KartShrinkType_OnChange(void); static void KartBumpSpark_OnChange(void); static void Schedule_OnChange(void); @@ -386,35 +383,6 @@ consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS] = { //Alam: Dummy for save #endif // SRB2kart -consvar_t cv_sneaker = CVAR_INIT ("sneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_rocketsneaker = CVAR_INIT ("rocketsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_invincibility = CVAR_INIT ("invincibility", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_banana = CVAR_INIT ("banana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_eggmanmonitor = CVAR_INIT ("eggmanmonitor", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_shrink = CVAR_INIT ("shrink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_thundershield = CVAR_INIT ("thundershield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_hyudoro = CVAR_INIT ("hyudoro", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_pogospring = CVAR_INIT ("pogospring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_superring = CVAR_INIT ("superring", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_landmine = CVAR_INIT ("landmine", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_bubbleshield = CVAR_INIT ("bubbleshield", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_flameshield = CVAR_INIT ("flameshield", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); - -consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_triplebanana = CVAR_INIT ("triplebanana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_decabanana = CVAR_INIT ("decabanana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_tripleorbinaut = CVAR_INIT ("tripleorbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_quadorbinaut = CVAR_INIT ("quadorbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_dualjawz = CVAR_INIT ("dualjawz", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); - static CV_PossibleValue_t kartminimap_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}}; consvar_t cv_kartminimap = CVAR_INIT ("kartminimap", "4", CV_SAVE, kartminimap_cons_t, NULL); consvar_t cv_kartcheck = CVAR_INIT ("kartcheck", "Yes", CV_SAVE, CV_YesNo, NULL); @@ -601,12 +569,6 @@ consvar_t cv_kartspbdist = CVAR_INIT ("kartspbdist", "4432", CV_NETVAR|CV_CHEAT| consvar_t cv_kartlegacyspbdist = CVAR_INIT ("kartlegacyspbdist", "2216", CV_NETVAR|CV_CHEAT|CV_GUARD, spbdist_cons_t, NULL); #undef MAXODDSDIST -// Items with alternative types -static CV_PossibleValue_t kartitemtype_cons_t[] = {{KARTITEM_NORMAL, "Legacy"}, {KARTITEM_ALTERN, "Alternative"}, {0, NULL}}; -consvar_t cv_kartinvintype = CVAR_INIT ("kartinvintype", "Legacy", CV_NETVAR|CV_CALL, kartitemtype_cons_t, KartInvinType_OnChange); -consvar_t cv_kartshrinktype = CVAR_INIT ("kartshrinktype", "Legacy", CV_NETVAR|CV_CALL, kartitemtype_cons_t, KartShrinkType_OnChange); -consvar_t cv_karteggmantype = CVAR_INIT ("karteggmantype", "Legacy", CV_NETVAR|CV_CALL, kartitemtype_cons_t, KartEggmanType_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); @@ -631,23 +593,7 @@ consvar_t cv_kartflame_offroadburn = CVAR_INIT ("kartflame_offroadburn", "Off", static CV_PossibleValue_t kartairsquish_cons_t[] = {{1, "Squish"}, {2, "Flip-over"}, {0, "None"}, {0, NULL}}; consvar_t cv_kartairsquish = CVAR_INIT ("kartairsquish", "None", CV_NETVAR, kartairsquish_cons_t, NULL); -static CV_PossibleValue_t kartdebugitem_cons_t[] = -{ -#define FOREACH( name, n ) { n, #name } - KART_ITEM_ITERATOR, -#undef FOREACH - {0} -}; -consvar_t cv_kartdebugitem = CVAR_INIT ("kartdebugitem", "NONE", CV_NETVAR|CV_CHEAT, kartdebugitem_cons_t, NULL); -static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}}; -consvar_t cv_kartdebugamount = CVAR_INIT ("kartdebugamount", "1", CV_NETVAR|CV_CHEAT, kartdebugamount_cons_t, NULL); consvar_t cv_kartdebugshrink = CVAR_INIT ("kartdebugshrink", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -#ifdef DEVELOP -#define VALUE "Yes" -#else -#define VALUE "No" -#endif -#undef VALUE consvar_t cv_kartdebugdistribution = CVAR_INIT ("kartdebugdistribution", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); consvar_t cv_kartdebughuddrop = CVAR_INIT ("kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); @@ -6235,8 +6181,7 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) SINT8 item = READSINT8(*cp); UINT8 amt = READUINT8(*cp); - item = max(item, KITEM_SAD); - item = min(item, NUMKARTITEMS - 1); + item = CLAMP(item, KITEM_SAD, numkartitems - 1); K_StripItems(player); @@ -6252,10 +6197,7 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) } else { - // FIXME: we should have actual KITEM_ name array - const char *itemname = cv_kartdebugitem.PossibleValue[1 + item].strvalue; - - CV_CheaterWarning(playernum, va("give item %s x%d", itemname, amt)); + CV_CheaterWarning(playernum, va("give item %s x%d", item < 0 ? "SAD" : kartitems[item].name, amt)); } break; } @@ -6540,8 +6482,6 @@ static void Command_KartGiveItem_f(void) const char *name; INT32 item; - const char * str; - int i; ac = COM_Argc(); @@ -6553,7 +6493,7 @@ static void Command_KartGiveItem_f(void) } else { - item = NUMKARTITEMS; + item = numkartitems; name = COM_Argv(1); @@ -6569,18 +6509,18 @@ static void Command_KartGiveItem_f(void) CONS_Printf("\x83" "Autocomplete:\n"); /* then do very loose partial matching */ - for (i = 0; ( str = kartdebugitem_cons_t[i].strvalue ); ++i) + for (i = 0; i < numkartitems; i++) { - if (strcasestr(str, name) != NULL) + if (strcasestr(kartitems[i].name, name) != NULL) { - CONS_Printf("\x83\t%s\n", str); - item = kartdebugitem_cons_t[i].value; + CONS_Printf("\x83\t%s\n", kartitems[i].name); + item = i; } } } } - if (item < NUMKARTITEMS) + if (item < numkartitems) { INT32 amt; @@ -7828,60 +7768,6 @@ static void KartItemBreaker_OnChange(void) } } -static void KartInvinType_OnChange(void) -{ - if (K_CanChangeRules(false) == false) - { - return; - } - - if (leveltime < starttime) - { - CONS_Printf(M_GetText("Invincibility type has been changed to \"%s\".\n"), cv_kartinvintype.string); - invintype = (UINT8)cv_kartinvintype.value; - } - else - { - CONS_Printf(M_GetText("Invincibility type will be changed to \"%s\" next round.\n"), cv_kartinvintype.string); - } -} - -static void KartShrinkType_OnChange(void) -{ - if (K_CanChangeRules(false) == false) - { - return; - } - - if (leveltime < starttime) - { - CONS_Printf(M_GetText("Shrink type has been changed to \"%s\".\n"), cv_kartshrinktype.string); - shrinktype = (UINT8)cv_kartshrinktype.value; - } - else - { - CONS_Printf(M_GetText("Shrink type will be changed to \"%s\" next round.\n"), cv_kartshrinktype.string); - } -} - -static void KartEggmanType_OnChange(void) -{ - if (K_CanChangeRules(false) == false) - { - return; - } - - if (leveltime < starttime) - { - CONS_Printf(M_GetText("Eggman Monitor type has been changed to \"%s\".\n"), cv_karteggmantype.string); - eggmantype = (UINT8)cv_karteggmantype.value; - } - else - { - CONS_Printf(M_GetText("Eggman Monitor type will be changed to \"%s\" next round.\n"), cv_karteggmantype.string); - } -} - static void KartBumpSpark_OnChange(void) { if (K_CanChangeRules(false) == false) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 6d188f04d..f4d83f978 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -72,38 +72,6 @@ extern consvar_t cv_spectatorreentry, cv_antigrief; extern consvar_t cv_debugtraversemax; #endif -// SRB2kart items -extern consvar_t - cv_sneaker, - cv_rocketsneaker, - cv_invincibility, - cv_banana, - cv_eggmanmonitor, - cv_orbinaut, - cv_jawz, - cv_mine, - cv_ballhog, - cv_selfpropelledbomb, - cv_grow, - cv_shrink, - cv_thundershield, - cv_hyudoro, - cv_pogospring, - cv_kitchensink, - cv_superring, - cv_landmine, - cv_bubbleshield, - cv_flameshield; - -extern consvar_t - cv_dualsneaker, - cv_triplesneaker, - cv_triplebanana, - cv_decabanana, - cv_tripleorbinaut, - cv_quadorbinaut, - cv_dualjawz; - extern consvar_t cv_kartminimap; extern consvar_t cv_kartcheck; extern consvar_t cv_kartinvinsfx; @@ -160,6 +128,11 @@ extern consvar_t cv_kartstacking_bubble_speedboost; extern consvar_t cv_kartstacking_bubble_accelboost; extern consvar_t cv_kartstacking_bubble_stackable; +extern consvar_t cv_kartaltshrinktime; +extern consvar_t cv_kartstacking_altshrink_speedboost; +extern consvar_t cv_kartstacking_altshrink_accelboost; +extern consvar_t cv_kartstacking_altshrink_stackable; + extern consvar_t cv_kartstacking_start_speedboost; extern consvar_t cv_kartstacking_start_accelboost; extern consvar_t cv_kartstacking_start_stackable; @@ -200,7 +173,6 @@ extern consvar_t cv_kartbumpspark; extern consvar_t cv_kartbumpspring; extern consvar_t cv_kartslipdash; extern consvar_t cv_kartslopeboost; -extern consvar_t cv_kartinvintype; extern consvar_t cv_kartinvindist; extern consvar_t cv_kartinvindistmul; extern consvar_t cv_kartinvin_maxtime; diff --git a/src/d_player.h b/src/d_player.h index 979f1165f..a914f59da 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -137,61 +137,6 @@ typedef enum CR_ZOOMTUBE, } carrytype_t; // carry -/* -To use: #define FOREACH( name, number ) -Do with it whatever you want. -Run this macro, then #undef FOREACH afterward -*/ -#define KART_ITEM_ITERATOR \ - FOREACH (SAD, -1),\ - FOREACH (NONE, 0),\ - FOREACH (SNEAKER, 1),\ - FOREACH (ROCKETSNEAKER, 2),\ - FOREACH (INVINCIBILITY, 3),\ - FOREACH (BANANA, 4),\ - FOREACH (EGGMAN, 5),\ - FOREACH (ORBINAUT, 6),\ - FOREACH (JAWZ, 7),\ - FOREACH (MINE, 8),\ - FOREACH (BALLHOG, 9),\ - FOREACH (SPB, 10),\ - FOREACH (GROW, 11),\ - FOREACH (SHRINK, 12),\ - FOREACH (THUNDERSHIELD, 13),\ - FOREACH (HYUDORO, 14),\ - FOREACH (POGOSPRING, 15),\ - FOREACH (KITCHENSINK, 16),\ - FOREACH (SUPERRING, 17),\ - FOREACH (LANDMINE, 18),\ - FOREACH (BUBBLESHIELD, 19),\ - FOREACH (FLAMESHIELD, 20) - -typedef enum -{ -#define FOREACH( name, n ) KITEM_ ## name = n - KART_ITEM_ITERATOR, -#undef FOREACH - - NUMKARTITEMS, - - // Additional roulette numbers, only used for K_KartGetItemResult - KRITEM_DUALSNEAKER = NUMKARTITEMS, - KRITEM_TRIPLESNEAKER, - KRITEM_TRIPLEBANANA, - KRITEM_TENFOLDBANANA, - KRITEM_TRIPLEORBINAUT, - KRITEM_QUADORBINAUT, - KRITEM_DUALJAWZ, - - NUMBASEKARTRESULTS, - - // alt items implemented as separate things - KAITEM_EGGMINE = NUMBASEKARTRESULTS, // also landmine - KAITEM_ALTERNSHRINK, - - NUMKARTRESULTS -} kartitems_t; - typedef enum { KROULETTE_DISABLED, KROULETTE_ACTIVE, diff --git a/src/deh_lua.c b/src/deh_lua.c index 790fc9777..7b7b279be 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -439,6 +439,20 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word) } return luaL_error(L, "karthud '%s' could not be found.\n", word); } + else if (mathlib && fastncmp("KITEM_",word,6)) { + p = word+6; + if (fastcmp(p, "LIGHTNINGSHIELD")) + { + lua_pushinteger(L, KITEM_THUNDERSHIELD); + return 1; + } + for (i = 0; i < numkartitems; i++) + if (fastcmp(p, kartitems[i].name)) { + lua_pushinteger(L, i); + return 1; + } + return luaL_error(L, "kartitem '%s' could not be found.\n", word); + } else if (fastncmp("SKINCOLOR_",word,10)) { p = word+10; i = DEH_FindSkincolor(p); diff --git a/src/deh_lua.h b/src/deh_lua.h index 7b767f017..ed97a1418 100644 --- a/src/deh_lua.h +++ b/src/deh_lua.h @@ -27,6 +27,7 @@ extern "C" { #include "fastcmp.h" #include "lua_script.h" #include "lua_libs.h" +#include "k_items.h" #include "dehacked.h" #include "deh_tables.h" diff --git a/src/deh_tables.c b/src/deh_tables.c index c6b7c6b29..f714214c2 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1511,24 +1511,6 @@ struct int_const_s const INT_CONST[] = { {"BASEVIDWIDTH", BASEVIDWIDTH}, {"BASEVIDHEIGHT", BASEVIDHEIGHT}, - // SRB2Kart - // kartitems_t -#define FOREACH( name, n ) { TOSTR (KITEM_ ## name), KITEM_ ## name } - KART_ITEM_ITERATOR, // Actual items (can be set for k_itemtype) -#undef FOREACH - {"NUMKARTITEMS",NUMKARTITEMS}, - {"KRITEM_DUALSNEAKER",KRITEM_DUALSNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch) - {"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, - {"KRITEM_TRIPLEBANANA",KRITEM_TRIPLEBANANA}, - {"KRITEM_TENFOLDBANANA",KRITEM_TENFOLDBANANA}, - {"KRITEM_TRIPLEORBINAUT",KRITEM_TRIPLEORBINAUT}, - {"KRITEM_QUADORBINAUT",KRITEM_QUADORBINAUT}, - {"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ}, - {"NUMBASEKARTRESULTS",NUMBASEKARTRESULTS}, - {"KAITEM_EGGMINE", KAITEM_EGGMINE}, - {"KAITEM_ALTERNSHRINK", KAITEM_ALTERNSHRINK}, - {"NUMKARTRESULTS",NUMKARTRESULTS}, - // kartshields_t {"KSHIELD_NONE",KSHIELD_NONE}, {"KSHIELD_THUNDER",KSHIELD_THUNDER}, @@ -1537,9 +1519,6 @@ struct int_const_s const INT_CONST[] = { {"KSHIELD_FLAME",KSHIELD_FLAME}, {"NUMKARTSHIELDS",NUMKARTSHIELDS}, - // kartitems_t - {"KITEM_LIGHTNINGSHIELD",KITEM_THUNDERSHIELD}, - // kartroulette_t {"KROULETTE_DISABLED",KROULETTE_DISABLED}, {"KROULETTE_ACTIVE",KROULETTE_ACTIVE}, @@ -1685,9 +1664,6 @@ struct int_const_s const INT_CONST[] = { {"FACE_WANTED", FACE_WANTED}, {"FACE_MINIMAP", FACE_MINIMAP}, {"NUMFACES", NUMFACES}, - // alt item type - {"KARTITEM_NORMAL", KARTITEM_NORMAL}, - {"KARTITEM_ALTERN", KARTITEM_ALTERN}, // k_waypoint.h values {"DEFAULT_WAYPOINT_RADIUS",DEFAULT_WAYPOINT_RADIUS}, diff --git a/src/doomstat.h b/src/doomstat.h index 41173c77d..4c350d307 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -669,9 +669,6 @@ extern boolean franticitems; extern boolean encoremode, prevencoremode; extern boolean comeback; -extern UINT8 invintype; -extern UINT8 eggmantype; - extern SINT8 mostwanted; extern SINT8 battlewanted[4]; extern tic_t wantedcalcdelay; diff --git a/src/g_game.c b/src/g_game.c index b607d9cb0..3430f4113 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -61,8 +61,7 @@ #include "k_boss.h" #include "k_specialstage.h" #include "k_bot.h" -#include "k_odds.h" -#include "k_altshrink.h" +#include "k_items.h" #include "doomstat.h" #include "acs/interface.h" #include "k_director.h" @@ -300,9 +299,6 @@ boolean encoremode = false; // Encore Mode currently enabled? boolean prevencoremode; boolean franticitems; // Frantic items currently enabled? boolean comeback; // Battle Mode's karma comeback is on/off -// alt item values -UINT8 invintype; // How Invincibility functions. 0 for Legacy/Vanilla, 1 for Alternative. -UINT8 eggmantype; // How Eggman Monitor functions. 0 for Legacy/Vanilla, 1 for Alternative (Egg Mine). // Voting system INT16 votelevels[12][2]; // Levels that were rolled by the host @@ -314,7 +310,7 @@ SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points SINT8 mostwanted; // The "most wanted" (first in line) player. tic_t wantedcalcdelay; // Time before it recalculates WANTED tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded -// hyubgone was taken out back. See k_odds.c +// hyubgone was taken out back. See k_items.c tic_t mapreset; // Map reset delay when enough players have joined an empty game boolean thwompsactive; // Thwomps activate on lap 2 UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors diff --git a/src/info.c b/src/info.c index 9cef1eef2..9f25274a6 100644 --- a/src/info.c +++ b/src/info.c @@ -20,6 +20,7 @@ #include "d_main.h" #include "m_menu.h" #include "deh_tables.h" +#include "k_items.h" // Hey, moron! If you wanna change this table, you can just change the sprite enum in info/sprites.h, // so you don't have to copy and paste the list of sprite names back in here :^) @@ -233,4 +234,13 @@ void P_ResetData(INT32 flags) for (i = 0; i < MN_FIRSTFREESLOT; i++, name += strlen(name)+1) DEH_Link(name, &menudefs[i].info, &menunames); } + + // kartitems + if (init) + { + memset(kartitems, 0, sizeof(kartitems)); + K_InitializeItems(); + + numkartitems = KITEM_FIRSTFREESLOT; + } } diff --git a/src/k_altshrink.c b/src/k_altshrink.c deleted file mode 100644 index 202cc47d3..000000000 --- a/src/k_altshrink.c +++ /dev/null @@ -1,82 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -/// \file k_altshrink.c -/// \brief Alternative Shrink item type functions. - -#include "doomdef.h" -#include "doomtype.h" -#include "doomstat.h" - -#include "command.h" -#include "console.h" -#include "d_player.h" -#include "k_kart.h" -#include "k_altshrink.h" -#include "k_cluster.hpp" -#include "m_fixed.h" -#include "p_local.h" - - -UINT8 shrinktype; // How Shrink functions. 0 for Legacy/Vanilla, 1 for Alternative. - -void K_UpdateShrinkType(void) -{ - if (leveltime < starttime) - { - CONS_Printf(M_GetText("Shrink type has been changed to \"%s\".\n"), cv_kartshrinktype.string); - } - - shrinktype = (UINT8)cv_kartshrinktype.value; -} - -/** \brief Depending on the Shrink type set, this returns true or false if the player is shrunk. - - \param player (player_t) Player to test shrunken status for - \param legacy (boolean) Legacy shrink? - - \return void -*/ -boolean K_IsShrunkMode(const player_t *player, boolean legacy) -{ - boolean shrunk = K_IsShrunk(player); - boolean legacytype = (!K_IsKartItemAlternate(KITEM_SHRINK)); - - if (legacy) - { - return ((shrunk) && (legacytype)); - } - - return ((shrunk) && (!legacytype)); -} - -#define ALTSHRINK_EPSILON (320 * FRACUNIT) -#define NEIGHBOR_IFRAMES (TICRATE / 2) -#define BASE_IFRAMES (2 * TICRATE) - -void K_AltShrinkIFrames(player_t *player) -{ - vector3_t tempclusterpoint; - - // Find neighbors - INT32 N = K_CountNeighboringPlayers(player, ALTSHRINK_EPSILON, &tempclusterpoint); - - // For every neighbor, add some iframes for a clean breakaway. - player->flashing = (UINT16)min((INT32)(UINT16_MAX), BASE_IFRAMES + (NEIGHBOR_IFRAMES * N)); -} - -#define PITY_SHRINKINCREASE_BASE (3) -#define PITY_SHRINKINCREASE (TICRATE / 2) - -void K_AltShrinkPityIncrease(player_t *player) -{ - // Increase your shrink timer by a little bit for every player you run into. - INT32 shrinktime = (UINT32)(K_GetShrinkTime(player)); - - fixed_t dimin = FRACUNIT; - - dimin = max(0, 5 - player->altshrinktimeshit) * FRACUNIT / 5; - - shrinktime = min(INT16_MAX, shrinktime + PITY_SHRINKINCREASE_BASE + FixedMul(PITY_SHRINKINCREASE, dimin)); - - player->growshrinktimer = ((INT16)shrinktime) * -1; -} \ No newline at end of file diff --git a/src/k_altshrink.h b/src/k_altshrink.h deleted file mode 100644 index a35640606..000000000 --- a/src/k_altshrink.h +++ /dev/null @@ -1,60 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -/// \file k_altshrink.h -/// \brief Alternative Shrink item type functions. - -#ifndef __K_ALTSHRINK__ -#define __K_ALTSHRINK__ - -#include "doomdef.h" -#include "d_player.h" // Need for player_t -#include "command.h" // Need for player_t -#include "m_fixed.h" -#include "k_kart.h" - -extern consvar_t cv_kartaltshrinktime; -extern consvar_t cv_kartshrinktype; - -extern consvar_t cv_kartstacking_altshrink_speedboost; -extern consvar_t cv_kartstacking_altshrink_accelboost; -extern consvar_t cv_kartstacking_altshrink_stackable; - -extern UINT8 shrinktype; - -#define ALTSHRINKTIME CV_Get(&cv_kartaltshrinktime) - -#define SHRINKSPEEDBOOST CV_Get(&cv_kartstacking_altshrink_speedboost) -#define SHRINKACCELBOOST CV_Get(&cv_kartstacking_altshrink_accelboost) -#define SHRINKSTACKABLE CV_Get(&cv_kartstacking_altshrink_stackable) - -/** \brief Returns true or false if the player is shrunk. - - \param player (player_t) Player to test shrunken status for - - \return Is this player shrunk? -*/ -FUNCINLINE static ATTRINLINE boolean K_IsShrunk(const player_t *player) -{ - return (player->growshrinktimer < 0); -} - -FUNCINLINE static ATTRINLINE INT16 K_GetShrinkTime(player_t *player) -{ - return (player->growshrinktimer * -1); -} - -FUNCINLINE static ATTRINLINE fixed_t K_AccomodateShrinkScaling(fixed_t x) -{ - return FixedDiv(x, SHRINK_SCALE); -} - -boolean K_IsShrunkMode(const player_t *player, boolean legacy); - -#define K_IsLegacyShrunk(player) (K_IsShrunkMode(player, true)) -#define K_IsAltShrunk(player) (K_IsShrunkMode(player, false)) - -void K_UpdateShrinkType(void); -void K_AltShrinkIFrames(player_t *player); -void K_AltShrinkPityIncrease(player_t *player); - -#endif // __K_ALTSHRINK__ \ No newline at end of file diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 2a4d02491..75fa915f2 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -44,6 +44,7 @@ #include "blan/b_soc.h" #include "v_video.h" // for debugging #include "k_waypoint.h" +#include "k_items.h" consvar_t cv_forcebots = CVAR_INIT ("kartforcebots", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); consvar_t cv_botcontrol = CVAR_INIT ("kartbotcontrol", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index 4ff9197cd..277d64552 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -29,7 +29,7 @@ #include "m_random.h" #include "r_things.h" // numskins #include "m_easing.h" -#include "k_odds.h" +#include "k_items.h" #include "k_waypoint.h" // Looks for players around the bot, and presses the item button @@ -1155,7 +1155,7 @@ static void K_BotItemRouletteMash(botdata_t *bd, const player_t *player) } } - if (player->rings < 0 && cv_superring.value && K_RingsActive()) + if (player->rings < 0 && K_ItemResultEnabled("superring") && K_RingsActive()) { // Uh oh, we need a loan! // It'll be better in the long run for bots to lose an item set for 5-15 free rings. diff --git a/src/k_botsearch.cpp b/src/k_botsearch.cpp index 1597596c4..0d44462d1 100644 --- a/src/k_botsearch.cpp +++ b/src/k_botsearch.cpp @@ -33,6 +33,7 @@ #include "p_slopes.h" // P_GetZAt #include "m_perfstats.h" #include "k_objects.h" +#include "k_items.h" #include "blan/b_soc.h" diff --git a/src/k_collide.c b/src/k_collide.c index 3a2842817..234d05528 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -2,13 +2,12 @@ /// \brief SRB2Kart item collision hooks #include "k_collide.h" -#include "k_altshrink.h" #include "k_stats.h" #include "doomstat.h" #include "doomtype.h" #include "p_mobj.h" #include "k_kart.h" -#include "k_odds.h" +#include "k_items.h" #include "p_local.h" #include "s_sound.h" #include "r_main.h" // R_PointToAngle2, R_PointToDist2 diff --git a/src/k_hud.c b/src/k_hud.c index 30d5252e0..a807dbdd6 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -17,7 +17,7 @@ #include "k_boss.h" #include "k_color.h" #include "k_director.h" -#include "k_odds.h" +#include "k_items.h" #include "p_mobj.h" #include "screen.h" #include "doomtype.h" @@ -186,26 +186,6 @@ static patch_t *kp_itemmulsticker[4]; static patch_t *kp_itemx; static patch_t *kp_sadface[2]; -static patch_t *kp_sneaker[4]; -static patch_t *kp_rocketsneaker[2]; -static patch_t *kp_invincibility[13]; -static patch_t *kp_banana[5]; -static patch_t *kp_eggman[2]; -static patch_t *kp_orbinaut[5]; -static patch_t *kp_jawz[3]; -static patch_t *kp_mine[2]; -static patch_t *kp_ballhog[2]; -static patch_t *kp_selfpropelledbomb[2]; -static patch_t *kp_grow[2]; -static patch_t *kp_shrink[2]; -static patch_t *kp_thundershield[2]; -static patch_t *kp_hyudoro[2]; -static patch_t *kp_pogospring[2]; -static patch_t *kp_kitchensink[2]; -static patch_t *kp_superring[2]; -static patch_t *kp_landmine[2]; -static patch_t *kp_bubbleshield[2]; -static patch_t *kp_flameshield[2]; static patch_t *kp_check[6]; @@ -540,87 +520,31 @@ void K_LoadKartHUDGraphics(void) // Kart Item Windows HU_UpdatePatch(&kp_itembg[0], "K_ITBG"); HU_UpdatePatch(&kp_itembg[1], "K_ITBGD"); + HU_UpdatePatch(&kp_itembg[2], "K_ISBG"); + HU_UpdatePatch(&kp_itembg[3], "K_ISBGD"); HU_UpdatePatch(&kp_itembg[4], "K_ITBC"); HU_UpdatePatch(&kp_itembg[5], "K_ITBCD"); + HU_UpdatePatch(&kp_itembg[6], "K_ISBC"); + HU_UpdatePatch(&kp_itembg[7], "K_ISBCD"); HU_UpdatePatch(&kp_itemtimer[0], "K_ITIMER"); + HU_UpdatePatch(&kp_itemtimer[1], "K_ISIMER"); HU_UpdatePatch(&kp_itemmulsticker[0], "K_ITMUL"); + HU_UpdatePatch(&kp_itemmulsticker[1], "K_ISMUL"); HU_UpdatePatch(&kp_itemmulsticker[2], "K_ITMULC"); + HU_UpdatePatch(&kp_itemmulsticker[3], "K_ISMULC"); HU_UpdatePatch(&kp_itemx, "K_ITX"); HU_UpdatePatch(&kp_sadface[0], "K_ITSAD"); - HU_UpdatePatch(&kp_sneaker[0], "K_ITSHOE"); - HU_UpdatePatch(&kp_sneaker[1], "K_ITSHO2"); - HU_UpdatePatch(&kp_sneaker[2], "K_ITSHO3"); - HU_UpdatePatch(&kp_rocketsneaker[0], "K_ITRSHE"); - - sprintf(buffer, "K_ITINVx"); - for (i = 0; i < 7; i++) - { - buffer[7] = '1'+i; - HU_UpdatePatch(&kp_invincibility[i], "%s", buffer); - } - HU_UpdatePatch(&kp_banana[0], "K_ITBANA"); - HU_UpdatePatch(&kp_banana[1], "K_ITBAN2"); - HU_UpdatePatch(&kp_banana[2], "K_ITBAN3"); - HU_UpdatePatch(&kp_banana[3], "K_ITBAN4"); - HU_UpdatePatch(&kp_eggman[0], "K_ITEGGM"); - sprintf(buffer, "K_ITORBx"); - for (i = 0; i < 4; i++) - { - buffer[7] = '1'+i; - HU_UpdatePatch(&kp_orbinaut[i], "%s", buffer); - } - HU_UpdatePatch(&kp_jawz[0], "K_ITJAWZ"); - HU_UpdatePatch(&kp_jawz[1], "K_ITJAW2"); - HU_UpdatePatch(&kp_mine[0], "K_ITMINE"); - HU_UpdatePatch(&kp_ballhog[0], "K_ITBHOG"); - HU_UpdatePatch(&kp_selfpropelledbomb[0], "K_ITSPB"); - HU_UpdatePatch(&kp_grow[0], "K_ITGROW"); - HU_UpdatePatch(&kp_shrink[0], "K_ITSHRK"); - HU_UpdatePatch(&kp_thundershield[0], "K_ITTHNS"); - HU_UpdatePatch(&kp_hyudoro[0], "K_ITHYUD"); - HU_UpdatePatch(&kp_pogospring[0], "K_ITPOGO"); - HU_UpdatePatch(&kp_kitchensink[0], "K_ITSINK"); - HU_UpdatePatch(&kp_superring[0], "K_ITRING"); - HU_UpdatePatch(&kp_landmine[0], "K_ITLNDM"); - HU_UpdatePatch(&kp_bubbleshield[0], "K_ITBUBS"); - HU_UpdatePatch(&kp_flameshield[0], "K_ITFLMS"); - - // Splitscreen - HU_UpdatePatch(&kp_itembg[2], "K_ISBG"); - HU_UpdatePatch(&kp_itembg[3], "K_ISBGD"); - HU_UpdatePatch(&kp_itembg[6], "K_ISBC"); - HU_UpdatePatch(&kp_itembg[7], "K_ISBCD"); - HU_UpdatePatch(&kp_itemtimer[1], "K_ISIMER"); - HU_UpdatePatch(&kp_itemmulsticker[1], "K_ISMUL"); - HU_UpdatePatch(&kp_itemmulsticker[3], "K_ISMULC"); - HU_UpdatePatch(&kp_sadface[1], "K_ISSAD"); - HU_UpdatePatch(&kp_sneaker[3], "K_ISSHOE"); - HU_UpdatePatch(&kp_rocketsneaker[1], "K_ISRSHE"); - sprintf(buffer, "K_ISINVx"); - for (i = 0; i < 6; i++) + + for (i = 0; i < numkartitems; i++) { - buffer[7] = '1'+i; - HU_UpdatePatch(&kp_invincibility[i+7], "%s", buffer); + kartitem_t *item = &kartitems[i]; + for (j = 0; j < item->graphics[0].numpatches; j++) + HU_UpdatePatch(&item->graphics[0].patches[j], item->graphics[0].patchnames[j]); + for (j = 0; j < item->graphics[1].numpatches; j++) + HU_UpdatePatch(&item->graphics[1].patches[j], item->graphics[1].patchnames[j]); } - HU_UpdatePatch(&kp_banana[4], "K_ISBANA"); - HU_UpdatePatch(&kp_eggman[1], "K_ISEGGM"); - HU_UpdatePatch(&kp_orbinaut[4], "K_ISORBN"); - HU_UpdatePatch(&kp_jawz[2], "K_ISJAWZ"); - HU_UpdatePatch(&kp_mine[1], "K_ISMINE"); - HU_UpdatePatch(&kp_ballhog[1], "K_ISBHOG"); - HU_UpdatePatch(&kp_selfpropelledbomb[1], "K_ISSPB"); - HU_UpdatePatch(&kp_grow[1], "K_ISGROW"); - HU_UpdatePatch(&kp_shrink[1], "K_ISSHRK"); - HU_UpdatePatch(&kp_thundershield[1], "K_ISTHNS"); - HU_UpdatePatch(&kp_hyudoro[1], "K_ISHYUD"); - HU_UpdatePatch(&kp_pogospring[1], "K_ISPOGO"); - HU_UpdatePatch(&kp_kitchensink[1], "K_ISSINK"); - HU_UpdatePatch(&kp_superring[1], "K_ISRING"); - HU_UpdatePatch(&kp_landmine[1], "K_ISLNDM"); - HU_UpdatePatch(&kp_bubbleshield[1], "K_ISBUBS"); - HU_UpdatePatch(&kp_flameshield[1], "K_ISFLMS"); // CHECK indicators sprintf(buffer, "K_CHECKx"); @@ -723,101 +647,20 @@ void K_LoadKartHUDGraphics(void) } } -// For the item toggle menu -const char *K_GetItemPatch(UINT8 item, boolean tiny) +patch_t *K_GetCachedItemPatch(SINT8 type, boolean tiny, UINT8 amount) { - switch (item) - { - case KITEM_SNEAKER: - return (tiny ? "K_ISSHOE" : "K_ITSHOE"); - case KITEM_ROCKETSNEAKER: - return (tiny ? "K_ISRSHE" : "K_ITRSHE"); - case KITEM_INVINCIBILITY: - return (tiny ? "K_ISINV1" : "K_ITINV1"); - case KITEM_BANANA: - return (tiny ? "K_ISBANA" : "K_ITBANA"); - case KITEM_EGGMAN: - return (tiny ? "K_ISEGGM" : "K_ITEGGM"); - case KITEM_ORBINAUT: - return (tiny ? "K_ISORBN" : "K_ITORB1"); - case KITEM_JAWZ: - return (tiny ? "K_ISJAWZ" : "K_ITJAWZ"); - case KITEM_MINE: - return (tiny ? "K_ISMINE" : "K_ITMINE"); - case KITEM_BALLHOG: - return (tiny ? "K_ISBHOG" : "K_ITBHOG"); - case KITEM_SPB: - return (tiny ? "K_ISSPB" : "K_ITSPB"); - case KITEM_GROW: - return (tiny ? "K_ISGROW" : "K_ITGROW"); - case KITEM_SHRINK: - return (tiny ? "K_ISSHRK" : "K_ITSHRK"); - case KITEM_THUNDERSHIELD: - return (tiny ? "K_ISTHNS" : "K_ITTHNS"); - case KITEM_HYUDORO: - return (tiny ? "K_ISHYUD" : "K_ITHYUD"); - case KITEM_POGOSPRING: - return (tiny ? "K_ISPOGO" : "K_ITPOGO"); - case KITEM_KITCHENSINK: - return (tiny ? "K_ISSINK" : "K_ITSINK"); - case KITEM_SUPERRING: - return (tiny ? "K_ISRING" : "K_ITRING"); - case KITEM_LANDMINE: - return (tiny ? "K_ISLNDM" : "K_ITLNDM"); - case KITEM_BUBBLESHIELD: - return (tiny ? "K_ISBUBS" : "K_ITBUBS"); - case KITEM_FLAMESHIELD: - return (tiny ? "K_ISFLMS" : "K_ITFLMS"); - case KRITEM_DUALSNEAKER: - return (tiny ? "K_ISSHOE" : "K_ITSHO2"); - case KRITEM_TRIPLESNEAKER: - return (tiny ? "K_ISSHOE" : "K_ITSHO3"); - case KRITEM_TRIPLEORBINAUT: - return (tiny ? "K_ISORBN" : "K_ITORB3"); - case KRITEM_DUALJAWZ: - return (tiny ? "K_ISJAWZ" : "K_ITJAW2"); - case KRITEM_TRIPLEBANANA: - return (tiny ? "K_ISBANA" : "K_ITBAN3"); - case KRITEM_TENFOLDBANANA: - return (tiny ? "K_ISBANA" : "K_ITBAN4"); - case KRITEM_QUADORBINAUT: - return (tiny ? "K_ISORBN" : "K_ITORB4"); - default: - return (tiny ? "K_ISSAD" : "K_ITSAD"); - } -} - -static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset) -{ - patch_t **kp[1 + NUMKARTITEMS] = { - kp_sadface, - NULL, - kp_sneaker, - kp_rocketsneaker, - kp_invincibility, - kp_banana, - kp_eggman, - kp_orbinaut, - kp_jawz, - kp_mine, - kp_ballhog, - kp_selfpropelledbomb, - kp_grow, - kp_shrink, - kp_thundershield, - kp_hyudoro, - kp_pogospring, - kp_kitchensink, - kp_superring, - kp_landmine, - kp_bubbleshield, - kp_flameshield, - }; - - if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS)) - return kp[item - KITEM_SAD][offset]; - else + if (type == KITEM_SAD) + return tiny ? kp_sadface[1] : kp_sadface[0]; + else if (type <= KITEM_NONE || type >= numkartitems) return NULL; + + kartitem_t *item = &kartitems[type]; + kartitemgraphics_t *graphics = &item->graphics[tiny ? 1 : 0]; + + if (item->animated) + return graphics->patches[(leveltime % (graphics->numpatches*3)) / 3]; + else + return graphics->patches[CLAMP(amount - 1, 0, graphics->numpatches - 1)]; } //} @@ -1330,10 +1173,9 @@ static void K_drawKartItem(void) // Why write V_DrawScaledPatch calls over and over when they're all the same? // Set to 'no item' just in case. - const UINT8 offset = ((r_splitscreen > 1) ? 1 : 0); + const boolean tiny = r_splitscreen > 1; patch_t *localpatch = kp_nodraw; patch_t *localbg; - patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]); boolean dark = false; INT32 fx = 0, fy = 0, fflags = 0; // final coords for hud and flags... INT32 numberdisplaymin = 2; @@ -1351,26 +1193,7 @@ static void K_drawKartItem(void) if (K_GetHudColor()) localcolor = K_GetHudColor(); - switch (item) - { - case KITEM_SNEAKER: - localpatch = kp_sneaker[offset ? 3: 0]; - break; - case KITEM_BANANA: - localpatch = kp_banana[offset ? 4: 0]; - break; - case KITEM_ORBINAUT: - localpatch = kp_orbinaut[3+offset]; - break; - case KITEM_JAWZ: - localpatch = kp_jawz[offset ? 2: 0]; - break; - case KITEM_INVINCIBILITY: - localpatch = localinv; - break; - default: - localpatch = K_GetCachedItemPatch(item, offset); - } + localpatch = K_GetCachedItemPatch(item, tiny, 0); } else { @@ -1381,18 +1204,18 @@ static void K_drawKartItem(void) if (stplyr->stolentimer > 0) { if (leveltime & 2) - localpatch = kp_hyudoro[offset]; + localpatch = K_GetCachedItemPatch(KITEM_HYUDORO, tiny, 0); else localpatch = kp_nodraw; } else if ((stplyr->stealingtimer > 0) && (leveltime & 2)) { - localpatch = kp_hyudoro[offset]; + localpatch = K_GetCachedItemPatch(KITEM_HYUDORO, tiny, 0); } else if (stplyr->eggmanexplode > 1) { if (leveltime & 1) - localpatch = kp_eggman[offset]; + localpatch = K_GetCachedItemPatch(KITEM_EGGMAN, tiny, 0); else localpatch = kp_nodraw; } @@ -1401,7 +1224,7 @@ static void K_drawKartItem(void) itembar = FixedDiv(stplyr->rocketsneakertimer, itemtime*3); if (leveltime & 1) - localpatch = kp_rocketsneaker[offset]; + localpatch = K_GetCachedItemPatch(KITEM_ROCKETSNEAKER, tiny, 0); else localpatch = kp_nodraw; } @@ -1409,7 +1232,6 @@ static void K_drawKartItem(void) { itembar = FixedDiv(stplyr->flametimer, itemtime*3); flamebar = FixedDiv(stplyr->flamestore, FLAMESTOREMAX); - localbg = kp_itembg[offset+1]; dark = true; if ((stplyr->flamestore >= FLAMESTOREMAX-1) && (leveltime & 1)) @@ -1419,7 +1241,7 @@ static void K_drawKartItem(void) } if (leveltime & 1) - localpatch = kp_flameshield[offset]; + localpatch = K_GetCachedItemPatch(KITEM_FLAMESHIELD, tiny, 0); else localpatch = kp_nodraw; } @@ -1429,7 +1251,7 @@ static void K_drawKartItem(void) itembar = FixedDiv(stplyr->growcancel, 26); if (leveltime & 1) - localpatch = kp_grow[offset]; + localpatch = K_GetCachedItemPatch(KITEM_GROW, tiny, 0); else localpatch = kp_nodraw; } @@ -1441,13 +1263,13 @@ static void K_drawKartItem(void) flamebar = FixedDiv(stplyr->invincibilitycancel, 26); if (leveltime & 1) - localpatch = localinv; + localpatch = K_GetCachedItemPatch(KITEM_INVINCIBILITY, tiny, 0); else localpatch = kp_nodraw; } else if (K_GetShieldFromPlayer(stplyr) == KSHIELD_BUBBLE) { - localpatch = kp_bubbleshield[offset]; + localpatch = K_GetCachedItemPatch(KITEM_BUBBLESHIELD, tiny, 0); dark = true; if (stplyr->bubbleblowup > 0 && leveltime & 1) @@ -1461,7 +1283,7 @@ static void K_drawKartItem(void) else if (stplyr->sadtimer > 0) { if (leveltime & 2) - localpatch = kp_sadface[offset]; + localpatch = kp_sadface[tiny ? 1 : 0]; else localpatch = kp_nodraw; } @@ -1470,43 +1292,15 @@ static void K_drawKartItem(void) if (stplyr->itemamount <= 0) return; - switch(stplyr->itemtype) + localpatch = K_GetCachedItemPatch(stplyr->itemtype, tiny, stplyr->itemamount); + if (localpatch == NULL) + localpatch = kp_nodraw; // diagnose underflows + + if (stplyr->itemtype > 0 && stplyr->itemtype < numkartitems) { - case KITEM_SNEAKER: - localpatch = kp_sneaker[(offset ? 3 : min(stplyr->itemamount-1, 2))]; - numberdisplaymin = 4; - numberdisplaymin = offset ? 2 : 4; - break; - case KITEM_INVINCIBILITY: - localpatch = localinv; - localbg = kp_itembg[offset+1]; - break; - case KITEM_BANANA: - localpatch = kp_banana[(offset ? 4 : min(stplyr->itemamount-1, 3))]; - numberdisplaymin = offset ? 2 : 5; - break; - case KITEM_ORBINAUT: - localpatch = kp_orbinaut[(offset ? 4 : min(stplyr->itemamount-1, 3))]; - numberdisplaymin = offset ? 2 : 5; - break; - case KITEM_JAWZ: - localpatch = kp_jawz[(offset ? 2 : min(stplyr->itemamount-1, 1))]; - numberdisplaymin = 3; - numberdisplaymin = offset ? 2 : 3; - break; - case KITEM_SPB: - case KITEM_THUNDERSHIELD: - case KITEM_BUBBLESHIELD: - case KITEM_FLAMESHIELD: - dark = true; - /*FALLTHRU*/ - - default: - localpatch = K_GetCachedItemPatch(stplyr->itemtype, offset); - - if (localpatch == NULL) - localpatch = kp_nodraw; // diagnose underflows - break; + kartitem_t *item = &kartitems[stplyr->itemtype]; + numberdisplaymin = item->animated ? 2 : item->graphics[tiny ? 1 : 0].numpatches + 1; + dark = item->darkbg; } if ((stplyr->itemflags & IF_ITEMOUT) && !(leveltime & 1)) @@ -1532,7 +1326,7 @@ static void K_drawKartItem(void) } } - localbg = K_getItemBoxPatch((boolean)offset, dark); + localbg = K_getItemBoxPatch(tiny, dark); drawinfo_t info; K_getItemBoxDrawinfo(&info); fx = info.x; @@ -1554,7 +1348,7 @@ static void K_drawKartItem(void) if (cv_fancyroulette.value && stplyr->itemroulette && !stplyr->deadtimer) { fixed_t frac = R_GetTimeFrac(RTF_LEVEL); - UINT8 fancystep = (offset ? 6 : 10); + UINT8 fancystep = tiny ? 6 : 10; fixed_t fancyoffset = (stplyr->itemroulette % 3)-1; if (fancyoffset != 0) @@ -1569,10 +1363,10 @@ static void K_drawKartItem(void) // Then, the numbers: if (stplyr->itemamount >= numberdisplaymin && !stplyr->itemroulette) { - localbg = K_getItemMulPatch((boolean)offset); + localbg = K_getItemMulPatch(tiny); V_DrawMappedPatch(fx + (flipamount ? 48 : 0), fy, V_HUDTRANS|fflags|(flipamount ? V_FLIP : 0), localbg, colormap); // flip this graphic for p2 and p4 in split and shift it. V_DrawFixedPatch(fx<itemamount)); else @@ -1598,7 +1392,7 @@ static void K_drawKartItem(void) // Quick Eggman numbers if (stplyr->eggmanexplode > 1) - V_DrawScaledPatch(fx+17, fy+13-offset, V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->eggmanexplode))]); + V_DrawScaledPatch(fx+17, fy+13-(tiny ? 1 : 0), V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->eggmanexplode))]); } void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) @@ -5758,48 +5552,12 @@ K_drawMiniPing (void) } } -static patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item) -{ - UINT8 offset; - - item = K_ItemResultToType(item); - - switch (item) - { - case KITEM_INVINCIBILITY: - offset = 7; - break; - - case KITEM_BANANA: - offset = 4; - break; - - case KITEM_ORBINAUT: - offset = 4; - break; - - case KITEM_JAWZ: - offset = 2; - break; - - case KITEM_SNEAKER: - offset = 3; - break; - - default: - offset = 1; - } - - return K_GetCachedItemPatch(item, offset); -} - static void K_drawDistributionDebugger(void) { UINT8 useodds = 0; UINT8 pingame = 0, bestbumper = 0; UINT32 pdis = 0; INT32 i; - INT32 item; INT32 x = -9, y = -9; //boolean dontforcespb = false; boolean spbrush = false; @@ -5825,21 +5583,19 @@ static void K_drawDistributionDebugger(void) if (pingame == 1) { - if (stplyr->itemroulette && (stplyr->cmd.buttons & BT_ATTACK) && cv_superring.value && (K_RingsActive() == true)) - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SUPERRING)); + if (stplyr->itemroulette && stplyr->cmd.buttons & BT_ATTACK && K_ItemResultEnabled("superring") && K_RingsActive()) + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetCachedItemPatch(KITEM_SUPERRING, true, 0)); else - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SNEAKER)); + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetCachedItemPatch(KITEM_SNEAKER, true, 0)); V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", 200)); } else { - for (item = 1; item < NUMBASEKARTRESULTS; item++) + for (i = 0; i < numkartresults; i++) { - INT32 itemodds; - INT32 amount; - - itemodds = K_KartGetItemOdds( - useodds, item, + kartresult_t *result = &kartresults[i]; + INT32 itemodds = K_KartGetItemOdds( + useodds, result, stplyr->distancetofinish, stplyr->distancefromcluster, 0, @@ -5850,14 +5606,13 @@ static void K_drawDistributionDebugger(void) if (itemodds <= 0) continue; - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(item)); + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetCachedItemPatch(result->type, true, 0)); V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", itemodds)); // Display amount for multi-items - amount = K_ItemResultToAmount(item); - if (amount > 1) + if (result->amount > 1) { - V_DrawString(x+24, y+31, V_SPLITSCREEN|V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOTOP, va("x%d", amount)); + V_DrawString(x+24, y+31, V_SPLITSCREEN|V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOTOP, va("x%d", result->amount)); } diff --git a/src/k_hud.h b/src/k_hud.h index f330d950f..119dcffcc 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -95,11 +95,11 @@ void K_getRingsDrawinfo(drawinfo_t *out); void K_getMinimapDrawinfo(drawinfo_t *out); void K_getSlipstreamDrawinfo(drawinfo_t *out); void K_getLivesnStatsDrawinfo(drawinfo_t *out); -const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_ReloadHUDColorCvar(void); boolean K_UseColorHud(void); UINT8 K_GetHudColor(void); void K_LoadKartHUDGraphics(void); +patch_t *K_GetCachedItemPatch(SINT8 type, boolean tiny, UINT8 amount); void K_drawKartHUD(void); void K_drawKartFreePlay(void); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); diff --git a/src/k_odds.c b/src/k_items.c similarity index 56% rename from src/k_odds.c rename to src/k_items.c index 9fe28fcbc..679ebb273 100644 --- a/src/k_odds.c +++ b/src/k_items.c @@ -8,8 +8,8 @@ // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file k_odds.cpp -/// \brief Kart item odds systems. +/// \file k_items.c +/// \brief Kart item systems. // SRB2kart Roulette Code - Position Based @@ -33,41 +33,22 @@ #include "k_bot.h" #include "k_kart.h" #include "k_waypoint.h" -#include "k_altshrink.h" #include "k_cluster.hpp" -#include "k_odds.h" +#include "k_items.h" +#include "z_zone.h" -consvar_t *KartItemCVars[NUMKARTRESULTS-1] = -{ - &cv_sneaker, - &cv_rocketsneaker, - &cv_invincibility, - &cv_banana, - &cv_eggmanmonitor, - &cv_orbinaut, - &cv_jawz, - &cv_mine, - &cv_ballhog, - &cv_selfpropelledbomb, - &cv_grow, - &cv_shrink, - &cv_thundershield, - &cv_hyudoro, - &cv_pogospring, - &cv_kitchensink, - &cv_superring, - &cv_landmine, // FIXME: Kill it. - &cv_bubbleshield, - &cv_flameshield, - &cv_dualsneaker, - &cv_triplesneaker, - &cv_triplebanana, - &cv_decabanana, - &cv_tripleorbinaut, - &cv_quadorbinaut, - &cv_dualjawz -}; +kartitem_t kartitems[MAXKARTITEMS] = {0}; +kartresult_t kartresults[MAXKARTRESULTS] = {0}; +UINT8 numkartitems = 0; +UINT8 numkartresults = 0; + +static CV_PossibleValue_t kartdebugitem_cons_t[MAXKARTITEMS] = {0}; +consvar_t cv_kartdebugitem = CVAR_INIT ("kartdebugitem", "NONE", CV_NETVAR|CV_CHEAT, kartdebugitem_cons_t, NULL); +static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}}; +consvar_t cv_kartdebugamount = CVAR_INIT ("kartdebugamount", "1", CV_NETVAR|CV_CHEAT, kartdebugamount_cons_t, NULL); + +static CV_PossibleValue_t kartitemtype_cons_t[] = {{0, "Legacy"}, {1, "Alternative"}, {0, NULL}}; #define NUMKARTODDS (MAXODDS*10) @@ -85,211 +66,354 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = #define REALMAXBATTLEPROB 10 #define MAXBATTLEPROBABILITY (REALMAXBATTLEPROB * BATTLEODDSMUL) -// Less ugly 2D arrays -// Expanded 16-tier useodds, for more flexible calculations. -// Item odds are now based around the max number being 75 as well. -static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][MAXODDS] = -{ - //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - //B C D E F G H I J K L M N O P Q - { 0, 0, 0, 0, 8, 24, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Sneaker - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 35, 42, 48, 37, 37}, // Rocket Sneaker - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 50, 75, 75}, // Invincibility - {35, 28, 22, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Banana - {18, 15, 12, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Eggman Monitor - {45, 28, 24, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Orbinaut - { 0, 11, 22, 9, 7, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Jawz - { 0, 0, 5, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Mine - { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Ballhog - { 0, 0, 2, 3, 4, 5, 6, 9, 10, 12, 8, 5, 2, 2, 0, 0}, // Self-Propelled Bomb - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 9, 12, 9, 0, 0, 0}, // Grow - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 7, 3, 0, 0}, // Shrink - {12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Thunder Shield - { 0, 0, 0, 0, 0, 2, 2, 4, 4, 2, 0, 0, 0, 0, 0, 0}, // Hyudoro - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Pogo Spring - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Kitchen Sink - { 7, 11, 15, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Super Ring - { 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Land Mine - { 0, 0, 0, 12, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Bubble Shield - { 0, 0, 0, 0, 0, 0, 2, 4, 12, 24, 27, 12, 7, 4, 0, 0}, // Flame Shield - { 0, 0, 0, 0, 0, 0, 8, 20, 40, 12, 0, 0, 0, 0, 0, 0}, // Sneaker x2 - { 0, 0, 0, 0, 0, 0, 0, 7, 35, 45, 60, 56, 52, 4, 0, 0}, // Sneaker x3 - { 0, 7, 7, 7, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Banana x3 - { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Banana x10 - { 0, 0, 0, 2, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Orbinaut x3 - { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Orbinaut x4 - { 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Jawz x2 - { 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Egg Mine - { 0, 0, 0, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Alt. Shrink -}; +static UINT8 oddstablelen[MAXODDSTABLES] = { MAXODDS, 2, 4 }; -static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = +static void K_RegisterItem(const char *name, boolean hasalt) { - //R S - { 2, 1 }, // Sneaker - { 0, 0 }, // Rocket Sneaker - { 4, 1 }, // Invincibility - { 0, 0 }, // Banana - { 1, 0 }, // Eggman Monitor - { 8, 0 }, // Orbinaut - { 8, 1 }, // Jawz - { 6, 1 }, // Mine - { 2, 1 }, // Ballhog - { 0, 0 }, // Self-Propelled Bomb - { 2, 1 }, // Grow - { 0, 0 }, // Shrink - { 4, 0 }, // Thunder Shield - { 2, 0 }, // Hyudoro - { 3, 0 }, // Pogo Spring - { 0, 0 }, // Kitchen Sink - { 0, 0 }, // Super Ring - { 2, 0 }, // Land Mine - { 1, 0 }, // Bubble Shield - { 1, 0 }, // Flame Shield - { 0, 0 }, // Sneaker x2 - { 0, 1 }, // Sneaker x3 - { 0, 0 }, // Banana x3 - { 1, 1 }, // Banana x10 - { 2, 0 }, // Orbinaut x3 - { 1, 1 }, // Orbinaut x4 - { 5, 1 }, // Jawz x2 - { 2, 0 }, // Egg Mine - { 1, 0 } // Alt. Shrink -}; + kartitem_t *item = &kartitems[numkartitems++]; -/* -static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = + item->name = name; + + if (hasalt) + { + char *cvname = malloc(strlen(name)+1 + 8); + sprintf(cvname, "altitem_%s", name); + strlwr(cvname); + + consvar_t *var = Z_Calloc(sizeof(consvar_t), PU_STATIC, &item->altcvar); + var->name = cvname; + var->defaultvalue = "Legacy"; + var->flags = CV_NETVAR/*|CV_CALL*/; + var->PossibleValue = kartitemtype_cons_t; + var->func = NULL; + CV_RegisterVar(var); + } + else + { + item->altcvar = NULL; + } + + kartdebugitem_cons_t[numkartitems - 1].strvalue = name; + kartdebugitem_cons_t[numkartitems - 1].value = numkartitems - 1; + kartdebugitem_cons_t[numkartitems].strvalue = NULL; + kartdebugitem_cons_t[numkartitems].value = 0; +} + +static void K_RegisterResult(const char *name, kartitemtype_e type, UINT8 amount, UINT8 flags) { - //M N O P - { 1, 1, 0, 0 }, // Sneaker - { 0, 0, 0, 0 }, // Rocket Sneaker - { 0, 0, 0, 0 }, // Invincibility - { 0, 0, 0, 0 }, // Banana - { 0, 0, 0, 0 }, // Eggman Monitor - { 1, 1, 0, 0 }, // Orbinaut - { 1, 1, 0, 0 }, // Jawz - { 0, 0, 0, 0 }, // Mine - { 0, 0, 0, 0 }, // Ballhog - { 0, 0, 0, 1 }, // Self-Propelled Bomb - { 0, 0, 0, 0 }, // Grow - { 0, 0, 0, 0 }, // Shrink - { 0, 0, 0, 0 }, // Thunder Shield - { 0, 0, 0, 0 }, // Hyudoro - { 0, 0, 0, 0 }, // Pogo Spring - { 0, 0, 0, 0 }, // Kitchen Sink - { 0, 0, 0, 0 }, // Super Ring - { 0, 0, 0, 0 }, // Land Mine - { 0, 0, 0, 0 }, // Bubble Shield - { 0, 0, 0, 0 }, // Flame Shield - { 0, 1, 1, 0 }, // Sneaker x2 - { 0, 0, 1, 1 }, // Sneaker x3 - { 0, 0, 0, 0 }, // Banana x3 - { 0, 0, 0, 0 }, // Banana x10 - { 0, 1, 1, 0 }, // Orbinaut x3 - { 0, 0, 1, 1 }, // Orbinaut x4 - { 0, 0, 1, 1 }, // Jawz x2 - { 0, 0, 0, 0 }, // Egg Mine - { 0, 0, 0, 0 } // Alt. Shrink -}; -*/ + kartresult_t *result = &kartresults[numkartresults++]; + result->name = name; + result->type = type; + result->amount = amount; + result->flags = flags; + + consvar_t *var = Z_Calloc(sizeof(consvar_t), PU_STATIC, &result->cvar); + var->name = name; + var->defaultvalue = "On"; + var->flags = CV_NETVAR|CV_CHEAT; + var->PossibleValue = CV_OnOff; + var->func = NULL; + CV_RegisterVar(var); +} + +kartresult_t *K_GetKartResult(const char *name) +{ + for (UINT8 i = 0; i < numkartresults; i++) + { + if (!strcmp(name, kartresults[i].name)) + return &kartresults[i]; + } + + return NULL; +} + +void K_InitializeItems(void) +{ + numkartitems = 0; + K_RegisterItem("NONE", false); + K_RegisterItem("SNEAKER", false); + K_RegisterItem("ROCKETSNEAKER", false); + K_RegisterItem("INVINCIBILITY", true); + K_RegisterItem("BANANA", false); + K_RegisterItem("EGGMAN", true); + K_RegisterItem("ORBINAUT", false); + K_RegisterItem("JAWZ", false); + K_RegisterItem("MINE", false); + K_RegisterItem("BALLHOG", false); + K_RegisterItem("SPB", false); + K_RegisterItem("GROW", false); + K_RegisterItem("SHRINK", true); + K_RegisterItem("THUNDERSHIELD", false); + K_RegisterItem("HYUDORO", false); + K_RegisterItem("POGOSPRING", false); + K_RegisterItem("KITCHENSINK", false); + K_RegisterItem("SUPERRING", false); + K_RegisterItem("LANDMINE", false); + K_RegisterItem("BUBBLESHIELD", false); + K_RegisterItem("FLAMESHIELD", false); + +#define A(item, amount, samount) \ + kartitems[item].graphics[0].numpatches = amount; \ + kartitems[item].graphics[1].numpatches = samount; \ + Z_Malloc(sizeof(const char *) * amount, PU_STATIC, &kartitems[item].graphics[0].patchnames); \ + Z_Malloc(sizeof(const char *) * samount, PU_STATIC, &kartitems[item].graphics[1].patchnames); \ + Z_Calloc(sizeof(patch_t *) * amount, PU_STATIC, &kartitems[item].graphics[0].patches); \ + Z_Calloc(sizeof(patch_t *) * samount, PU_STATIC, &kartitems[item].graphics[1].patches) + + A(KITEM_SNEAKER, 3, 1); + kartitems[KITEM_SNEAKER].graphics[0].patchnames[0] = "K_ITSHOE"; + kartitems[KITEM_SNEAKER].graphics[0].patchnames[1] = "K_ITSHO2"; + kartitems[KITEM_SNEAKER].graphics[0].patchnames[2] = "K_ITSHO3"; + kartitems[KITEM_SNEAKER].graphics[1].patchnames[0] = "K_ISSHOE"; + + A(KITEM_INVINCIBILITY, 7, 6); + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[0] = "K_ITINV1"; + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[1] = "K_ITINV2"; + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[2] = "K_ITINV3"; + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[3] = "K_ITINV4"; + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[4] = "K_ITINV5"; + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[5] = "K_ITINV6"; + kartitems[KITEM_INVINCIBILITY].graphics[0].patchnames[6] = "K_ITINV7"; + kartitems[KITEM_INVINCIBILITY].graphics[1].patchnames[0] = "K_ISINV1"; + kartitems[KITEM_INVINCIBILITY].graphics[1].patchnames[1] = "K_ISINV2"; + kartitems[KITEM_INVINCIBILITY].graphics[1].patchnames[2] = "K_ISINV3"; + kartitems[KITEM_INVINCIBILITY].graphics[1].patchnames[3] = "K_ISINV4"; + kartitems[KITEM_INVINCIBILITY].graphics[1].patchnames[4] = "K_ISINV5"; + kartitems[KITEM_INVINCIBILITY].graphics[1].patchnames[5] = "K_ISINV6"; + + A(KITEM_BANANA, 4, 1); + kartitems[KITEM_BANANA].graphics[0].patchnames[0] = "K_ITBANA"; + kartitems[KITEM_BANANA].graphics[0].patchnames[1] = "K_ITBAN2"; + kartitems[KITEM_BANANA].graphics[0].patchnames[2] = "K_ITBAN3"; + kartitems[KITEM_BANANA].graphics[0].patchnames[3] = "K_ITBAN4"; + kartitems[KITEM_BANANA].graphics[1].patchnames[0] = "K_ISBANA"; + + A(KITEM_ORBINAUT, 4, 1); + kartitems[KITEM_ORBINAUT].graphics[0].patchnames[0] = "K_ITORB1"; + kartitems[KITEM_ORBINAUT].graphics[0].patchnames[1] = "K_ITORB2"; + kartitems[KITEM_ORBINAUT].graphics[0].patchnames[2] = "K_ITORB3"; + kartitems[KITEM_ORBINAUT].graphics[0].patchnames[3] = "K_ITORB4"; + kartitems[KITEM_ORBINAUT].graphics[1].patchnames[0] = "K_ISORBN"; + + A(KITEM_JAWZ, 2, 1); + kartitems[KITEM_JAWZ].graphics[0].patchnames[0] = "K_ITJAWZ"; + kartitems[KITEM_JAWZ].graphics[0].patchnames[1] = "K_ITJAW2"; + kartitems[KITEM_JAWZ].graphics[1].patchnames[0] = "K_ISJAWZ"; +#undef A + +#define ONE(item, big, small) \ + kartitems[item].graphics[0].numpatches = 1; \ + kartitems[item].graphics[1].numpatches = 1; \ + Z_Malloc(sizeof(const char *), PU_STATIC, &kartitems[item].graphics[0].patchnames); \ + Z_Malloc(sizeof(const char *), PU_STATIC, &kartitems[item].graphics[1].patchnames); \ + Z_Calloc(sizeof(patch_t *), PU_STATIC, &kartitems[item].graphics[0].patches); \ + Z_Calloc(sizeof(patch_t *), PU_STATIC, &kartitems[item].graphics[1].patches); \ + kartitems[item].graphics[0].patchnames[0] = big; \ + kartitems[item].graphics[1].patchnames[0] = small + + ONE(KITEM_ROCKETSNEAKER, "K_ITRSHE", "K_ISRSHE"); + ONE(KITEM_EGGMAN, "K_ITEGGM", "K_ISEGGM"); + ONE(KITEM_MINE, "K_ITMINE", "K_ISMINE"); + ONE(KITEM_BALLHOG, "K_ITBHOG", "K_ISBHOG"); + ONE(KITEM_SPB, "K_ITSPB", "K_ISSPB"); + ONE(KITEM_GROW, "K_ITGROW", "K_ISGROW"); + ONE(KITEM_SHRINK, "K_ITSHRK", "K_ISSHRK"); + ONE(KITEM_THUNDERSHIELD, "K_ITTHNS", "K_ISTHNS"); + ONE(KITEM_HYUDORO, "K_ITHYUD", "K_ISHYUD"); + ONE(KITEM_POGOSPRING, "K_ITPOGO", "K_ISPOGO"); + ONE(KITEM_KITCHENSINK, "K_ITSINK", "K_ISSINK"); + ONE(KITEM_SUPERRING, "K_ITRING", "K_ISRING"); + ONE(KITEM_LANDMINE, "K_ITLNDM", "K_ISLNDM"); + ONE(KITEM_BUBBLESHIELD, "K_ITBUBS", "K_ISBUBS"); + ONE(KITEM_FLAMESHIELD, "K_ITFLMS", "K_ISFLMS"); +#undef ONE + + kartitems[KITEM_INVINCIBILITY].animated = true; + + kartitems[KITEM_INVINCIBILITY].darkbg = true; + kartitems[KITEM_SPB].darkbg = true; + kartitems[KITEM_THUNDERSHIELD].darkbg = true; + kartitems[KITEM_BUBBLESHIELD].darkbg = true; + kartitems[KITEM_FLAMESHIELD].darkbg = true; + + numkartresults = 0; + K_RegisterResult("sneaker", KITEM_SNEAKER, 1, 0); + K_RegisterResult("rocketsneaker", KITEM_ROCKETSNEAKER, 1, KRF_POWERITEM); + K_RegisterResult("invincibility", KITEM_INVINCIBILITY, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM); + K_RegisterResult("banana", KITEM_BANANA, 1, KRF_NOTNEAREND|KRF_NOTFORBOTTOM); + K_RegisterResult("eggman", KITEM_EGGMAN, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM|KRF_NOTNEAREND|KRF_NOTFORBOTTOM); + K_RegisterResult("orbinaut", KITEM_ORBINAUT, 1, 0); + K_RegisterResult("jawz", KITEM_JAWZ, 1, KRF_NOTFORBOTTOM|KRF_POWERITEM); + K_RegisterResult("mine", KITEM_MINE, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM); + K_RegisterResult("ballhog", KITEM_BALLHOG, 1, KRF_NOTFORBOTTOM|KRF_POWERITEM); + K_RegisterResult("spb", KITEM_SPB, 1, KRF_COOLDOWNONSTART|KRF_INDIRECTITEM|KRF_NOTNEAREND); + K_RegisterResult("grow", KITEM_GROW, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM); + K_RegisterResult("shrink", KITEM_SHRINK, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM|KRF_NOTNEAREND); + K_RegisterResult("thundershield", KITEM_THUNDERSHIELD, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM); + K_RegisterResult("hyudoro", KITEM_HYUDORO, 1, KRF_COOLDOWNONSTART); + K_RegisterResult("pogospring", KITEM_POGOSPRING, 1, 0); + K_RegisterResult("kitchensink", KITEM_KITCHENSINK, 1, 0); + K_RegisterResult("superring", KITEM_SUPERRING, 1, KRF_NOTNEAREND|KRF_NOTFORBOTTOM); + K_RegisterResult("landmine", KITEM_LANDMINE, 1, 0); + K_RegisterResult("bubbleshield", KITEM_BUBBLESHIELD, 1, KRF_NOTFORBOTTOM|KRF_POWERITEM); + K_RegisterResult("flameshield", KITEM_FLAMESHIELD, 1, KRF_COOLDOWNONSTART|KRF_POWERITEM); + + K_RegisterResult("dualsneaker", KITEM_SNEAKER, 2, 0); + K_RegisterResult("triplesneaker", KITEM_SNEAKER, 3, KRF_POWERITEM); + K_RegisterResult("triplebanana", KITEM_BANANA, 3, KRF_POWERITEM|KRF_NOTFORBOTTOM|KRF_NOTNEAREND); + K_RegisterResult("decabanana", KITEM_BANANA, 10, KRF_POWERITEM|KRF_NOTFORBOTTOM|KRF_NOTNEAREND); + K_RegisterResult("tripleorbinaut", KITEM_ORBINAUT, 3, KRF_NOTFORBOTTOM|KRF_POWERITEM); + K_RegisterResult("quadorbinaut", KITEM_ORBINAUT, 4, KRF_NOTFORBOTTOM|KRF_POWERITEM); + K_RegisterResult("dualjawz", KITEM_JAWZ, 2, KRF_NOTFORBOTTOM|KRF_POWERITEM); + +#define O(item, ...) memcpy(K_GetKartResult(#item)->odds[WHICH], (UINT8[MAXODDS]){__VA_ARGS__}, MAXODDS); +#define WHICH ODDS_RACE + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + O(sneaker, 0, 0, 0, 0, 8, 24, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Sneaker + O(rocketsneaker, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 35, 42, 48, 37, 37) // Rocket Sneaker + O(invincibility, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 50, 75, 75) // Invincibility + O(banana, 35, 28, 22, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Banana + O(eggman, 18, 15, 12, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Eggman Monitor + O(orbinaut, 45, 28, 24, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Orbinaut + O(jawz, 0, 11, 22, 9, 7, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Jawz + O(mine, 0, 0, 5, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Mine + O(ballhog, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Ballhog + O(spb, 0, 0, 2, 3, 4, 5, 6, 9, 10, 12, 8, 5, 2, 2, 0, 0) // Self-Propelled Bomb + O(grow, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 9, 12, 9, 0, 0, 0) // Grow + O(shrink, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 7, 3, 0, 0) // Shrink + O(thundershield, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Thunder Shield + O(hyudoro, 0, 0, 0, 0, 0, 2, 2, 4, 4, 2, 0, 0, 0, 0, 0, 0) // Hyudoro + O(pogospring, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Pogo Spring + O(kitchensink, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Kitchen Sink + O(superring, 7, 11, 15, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Super Ring + O(landmine, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Land Mine + O(bubbleshield, 0, 0, 0, 12, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Bubble Shield + O(flameshield, 0, 0, 0, 0, 0, 0, 2, 4, 12, 24, 27, 12, 7, 4, 0, 0) // Flame Shield + O(dualsneaker, 0, 0, 0, 0, 0, 0, 8, 20, 40, 12, 0, 0, 0, 0, 0, 0) // Sneaker x2 + O(triplesneaker, 0, 0, 0, 0, 0, 0, 0, 7, 35, 45, 60, 56, 52, 4, 0, 0) // Sneaker x3 + O(triplebanana, 0, 7, 7, 7, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Banana x3 + O(decabanana, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Banana x10 + O(tripleorbinaut, 0, 0, 0, 2, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Orbinaut x3 + O(quadorbinaut, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Orbinaut x4 + O(dualjawz, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // Jawz x2 + //{ 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Egg Mine + //{ 0, 0, 0, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Alt. Shrink +#undef WHICH + +#define WHICH ODDS_BATTLE + // R S + O(sneaker, 2, 1) // Sneaker + O(rocketsneaker, 0, 0) // Rocket Sneaker + O(invincibility, 4, 1) // Invincibility + O(banana, 0, 0) // Banana + O(eggman, 1, 0) // Eggman Monitor + O(orbinaut, 8, 0) // Orbinaut + O(jawz, 8, 1) // Jawz + O(mine, 6, 1) // Mine + O(ballhog, 2, 1) // Ballhog + O(spb, 0, 0) // Self-Propelled Bomb + O(grow, 2, 1) // Grow + O(shrink, 0, 0) // Shrink + O(thundershield, 4, 0) // Thunder Shield + O(hyudoro, 2, 0) // Hyudoro + O(pogospring, 3, 0) // Pogo Spring + O(kitchensink, 0, 0) // Kitchen Sink + O(superring, 0, 0) // Super Ring + O(landmine, 2, 0) // Land Mine + O(bubbleshield, 1, 0) // Bubble Shield + O(flameshield, 1, 0) // Flame Shield + O(dualsneaker, 0, 0) // Sneaker x2 + O(triplesneaker, 0, 1) // Sneaker x3 + O(triplebanana, 0, 0) // Banana x3 + O(decabanana, 1, 1) // Banana x10 + O(tripleorbinaut, 2, 0) // Orbinaut x3 + O(quadorbinaut, 1, 1) // Orbinaut x4 + O(dualjawz, 5, 1) // Jawz x2 + //{ 2, 0 }, // Egg Mine + //{ 1, 0 } // Alt. Shrink +#undef WHICH + +#define WHICH ODDS_SPECIAL + // M N O P + O(sneaker, 1, 1, 0, 0) // Sneaker + O(rocketsneaker, 0, 0, 0, 0) // Rocket Sneaker + O(invincibility, 0, 0, 0, 0) // Invincibility + O(banana, 0, 0, 0, 0) // Banana + O(eggman, 0, 0, 0, 0) // Eggman Monitor + O(orbinaut, 1, 1, 0, 0) // Orbinaut + O(jawz, 1, 1, 0, 0) // Jawz + O(mine, 0, 0, 0, 0) // Mine + O(ballhog, 0, 0, 0, 0) // Ballhog + O(spb, 0, 0, 0, 1) // Self-Propelled Bomb + O(grow, 0, 0, 0, 0) // Grow + O(shrink, 0, 0, 0, 0) // Shrink + O(thundershield, 0, 0, 0, 0) // Thunder Shield + O(hyudoro, 0, 0, 0, 0) // Hyudoro + O(pogospring, 0, 0, 0, 0) // Pogo Spring + O(kitchensink, 0, 0, 0, 0) // Kitchen Sink + O(superring, 0, 0, 0, 0) // Super Ring + O(landmine, 0, 0, 0, 0) // Land Mine + O(bubbleshield, 0, 0, 0, 0) // Bubble Shield + O(flameshield, 0, 0, 0, 0) // Flame Shield + O(dualsneaker, 0, 1, 1, 0) // Sneaker x2 + O(triplesneaker, 0, 0, 1, 1) // Sneaker x3 + O(triplebanana, 0, 0, 0, 0) // Banana x3 + O(decabanana, 0, 0, 0, 0) // Banana x10 + O(tripleorbinaut, 0, 1, 1, 0) // Orbinaut x3 + O(quadorbinaut, 0, 0, 1, 1) // Orbinaut x4 + O(dualjawz, 0, 0, 1, 1) // Jawz x2 + //{ 0, 0, 0, 0 }, // Egg Mine + //{ 0, 0, 0, 0 } // Alt. Shrink +#undef WHICH +#undef O // Cooldown time table; contains both base (index 0) and current (index 1) // times. Base times are in seconds, current times are in tics. -tic_t ItemBGone[NUMKARTRESULTS][2] = -{ - //BASE CURR - { 0, 0 }, // Null/Sad Face - { 0, 0 }, // Sneaker - { 0, 0 }, // Rocket Sneaker - { 0, 0 }, // Invincibility - { 0, 0 }, // Banana - { 10, 0 }, // Eggman Monitor - { 0, 0 }, // Orbinaut - { 5, 0 }, // Jawz - { 0, 0 }, // Mine - { 10, 0 }, // Ballhog - { 20, 0 }, // Self-Propelled Bomb - { 3, 0 }, // Grow - { 20, 0 }, // Shrink - { 0, 0 }, // Thunder Shield - { 20, 0 }, // Hyudoro - { 0, 0 }, // Pogo Spring - { 0, 0 }, // Kitchen Sink - { 0, 0 }, // Super Ring - { 0, 0 }, // Land Mine - { 5, 0 }, // Bubble Shield - { 8, 0 }, // Flame Shield - { 0, 0 }, // Sneaker x2 - { 0, 0 }, // Sneaker x3 - { 0, 0 }, // Banana x3 - { 30, 0 }, // Banana x10 - { 10, 0 }, // Orbinaut x3 - { 20, 0 }, // Orbinaut x4 - { 10, 0 }, // Jawz x2 - { 0, 0 }, // Egg Mine - { 5, 0 } // Alt. Shrink -}; +#define O(item, v) K_GetKartResult(#item)->basebgone = v; + O(sneaker, 0) // Sneaker + O(rocketsneaker, 0) // Rocket Sneaker + O(invincibility, 0) // Invincibility + O(banana, 0) // Banana + O(eggman, 10) // Eggman Monitor + O(orbinaut, 0) // Orbinaut + O(jawz, 5) // Jawz + O(mine, 0) // Mine + O(ballhog, 10) // Ballhog + O(spb, 20) // Self-Propelled Bomb + O(grow, 3) // Grow + O(shrink, 20) // Shrink + O(thundershield, 0) // Thunder Shield + O(hyudoro, 20) // Hyudoro + O(pogospring, 0) // Pogo Spring + O(kitchensink, 0) // Kitchen Sink + O(superring, 0) // Super Ring + O(landmine, 0) // Land Mine + O(bubbleshield, 5) // Bubble Shield + O(flameshield, 8) // Flame Shield + O(dualsneaker, 0) // Sneaker x2 + O(triplesneaker, 0) // Sneaker x3 + O(triplebanana, 0) // Banana x3 + O(decabanana, 30) // Banana x10 + O(tripleorbinaut, 10) // Orbinaut x3 + O(quadorbinaut, 20) // Orbinaut x4 + O(dualjawz, 10) // Jawz x2 + //O(, 0) // Egg Mine + //O(, 5) // Alt. Shrink +#undef O -// TODO: Vectorize all item tables and shove them into gamemode-uniqe pools (k_oddstable.cpp?). -// Basically necessary for any hopes of easy SOC support in the near future. - -static SINT8 K_GetAlternateVersion(SINT8 item) -{ - if (K_IsKartItemAlternate(item)) - { - switch(item) - { - /*case KITEM_INVINCIBILITY: - return KITEM_INVINCIBILITY;*/ - - case KITEM_EGGMAN: - return KAITEM_EGGMINE; - - case KITEM_SHRINK: - return KAITEM_ALTERNSHRINK; - - default: - break; - } - } - - return item; // Return ourselves; we don't have an alternative. + CV_RegisterVar(&cv_kartdebugitem); + CV_RegisterVar(&cv_kartdebugamount); } -/** \brief Sets the cooldown timer for an item. When active, the item is removed - * from all players' item pools for some time. - - \param item (SINT8) item to assign cooldown for - \param time (tic_t) cooldown time - - \return void -*/ -void K_SetBGone(SINT8 item, tic_t time) +void K_SetupItemOdds(void) { - ItemBGone[item][GONER_CURRCOOLDOWN] = time; + // TODO: something } -/** \brief Sets the cooldown timer for an item to its "base" (intended) time. - - \param item (SINT8) item to assign base cooldown for - - \return void -*/ -void K_SetBGoneToBase(SINT8 item) +boolean K_ItemResultEnabled(const char *name) { - ItemBGone[item][GONER_CURRCOOLDOWN] = (ItemBGone[item][GONER_BASECOOLDOWN] * TICRATE); -} - -/** \brief Gets the cooldown timer for an item. - - \param item (SINT8) item to retrieve cooldown for - \param base (bool) if true, returns the "base" (intended) cooldown instead - - \return (tic_t) cooldown time -*/ -tic_t K_GetBGone(SINT8 item, boolean base) -{ - return ItemBGone[item][base ? GONER_BASECOOLDOWN : GONER_CURRCOOLDOWN] * (base ? TICRATE : 1); + const kartresult_t *result = K_GetKartResult(name); + return result != NULL && result->cvar->value == 1; } /** \brief Are the odds in legacy distancing mode? @@ -362,86 +486,24 @@ static UINT32 K_IntDistanceForMap(fixed_t curx, destz / mapobjectscale); } -SINT8 K_ItemResultToType(SINT8 getitem) -{ - if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback) - { - if (getitem != 0) - { - CONS_Printf("ERROR: K_GetItemResultToItemType - Item roulette gave bad item (%d) :(\n", getitem); - } - - return KITEM_SAD; - } - - if (getitem >= NUMKARTITEMS) - { - switch (getitem) - { - case KRITEM_DUALSNEAKER: - case KRITEM_TRIPLESNEAKER: - return KITEM_SNEAKER; - - case KRITEM_TRIPLEBANANA: - case KRITEM_TENFOLDBANANA: - return KITEM_BANANA; - - case KRITEM_TRIPLEORBINAUT: - case KRITEM_QUADORBINAUT: - return KITEM_ORBINAUT; - - case KRITEM_DUALJAWZ: - return KITEM_JAWZ; - - default: - I_Error("K_ItemResultToType: Bad item redirect for result %d\n", getitem); - break; - } - } - - return getitem; -} - -UINT8 K_ItemResultToAmount(SINT8 getitem) -{ - switch (getitem) - { - case KRITEM_DUALSNEAKER: - case KRITEM_DUALJAWZ: - return 2; - - case KRITEM_TRIPLESNEAKER: - case KRITEM_TRIPLEBANANA: - case KRITEM_TRIPLEORBINAUT: - return 3; - - case KRITEM_QUADORBINAUT: - return 4; - - case KRITEM_TENFOLDBANANA: - return 10; - - default: - return 1; - } -} - /** \brief Prevent overpowered rolls while under the effects of Alt. Shrink. \param item the item to check \return Don't double for this item? */ -static boolean K_DontDoubleMyItems(SINT8 item) +static boolean K_DontDoubleMyItems(kartresult_t *result) { - return ((item == KITEM_BALLHOG) || (item == KRITEM_TENFOLDBANANA) - || (item == KRITEM_TRIPLEORBINAUT) - || (item == KRITEM_QUADORBINAUT) || (item == KRITEM_TRIPLESNEAKER) - || (item == KRITEM_DUALJAWZ) || (item == KITEM_SPB) - || (item == KITEM_INVINCIBILITY) || (item == KITEM_GROW) - || (item == KITEM_BUBBLESHIELD) || (item == KITEM_FLAMESHIELD) - || (item == KITEM_ROCKETSNEAKER) || (item == KITEM_SHRINK) - || (item == KITEM_HYUDORO)); + return result->type == KITEM_BALLHOG || result->type == KITEM_SPB + || result->type == KITEM_INVINCIBILITY || result->type == KITEM_GROW + || result->type == KITEM_BUBBLESHIELD || result->type == KITEM_FLAMESHIELD + || result->type == KITEM_ROCKETSNEAKER || result->type == KITEM_SHRINK + || result->type == KITEM_HYUDORO + || (result->type == KITEM_BANANA && result->amount >= 4) + || (result->type == KITEM_ORBINAUT && result->amount >= 3) + || (result->type == KITEM_SNEAKER && result->amount >= 3) + || (result->type == KITEM_JAWZ && result->amount >= 2) + || result->type >= KITEM_FIRSTFREESLOT; // TODO: excludes custom items for now } /** \brief Item Roulette for Kart @@ -451,31 +513,35 @@ static boolean K_DontDoubleMyItems(SINT8 item) \return void */ -static void K_KartGetItemResult(player_t *player, SINT8 getitem) +static void K_KartGetItemResult(player_t *player, const char *name) { - SINT8 trueitem = K_GetAlternateVersion(getitem); + kartresult_t *result = K_GetKartResult(name); + K_BotResetItemConfirm(player, true); - if (trueitem == KITEM_SPB || (trueitem == KITEM_SHRINK)) // Indirect items + if (result == NULL) + { + player->itemtype = KITEM_SAD; + player->itemamount = 1; + return; + } + + if (result->type == KITEM_SPB || result->type == KITEM_SHRINK) // Indirect items { indirectitemcooldown = 20*TICRATE; } - else if (K_GetBGone(trueitem, true) > 0) // Item cooldowns + else if (result->basebgone > 0) // Item cooldowns { - K_SetBGoneToBase(trueitem); + result->bgone = result->basebgone * TICRATE; } - K_BotResetItemConfirm(player, true); + player->itemtype = result->type; + UINT8 itemamount = result->amount; - player->itemtype = K_ItemResultToType(getitem); - UINT8 itemamount = K_ItemResultToAmount(getitem); - - if (K_IsAltShrunk(player) && (!K_DontDoubleMyItems(getitem))) + if (K_IsAltShrunk(player) && (!K_DontDoubleMyItems(result))) { itemamount *= 2; } - if (cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == player->itemtype && cv_kartdebugamount.value > 1) - itemamount = cv_kartdebugamount.value; player->itemamount = itemamount; } @@ -595,9 +661,9 @@ static INT32 K_KartGetInvincibilityOdds(UINT32 dist) #undef FRAC_3h // Assigns general cooldowns to shield items. -void K_KartHandleShieldCooldown(SINT8 item) +void K_KartHandleShieldCooldown(kartitemtype_e item) { - INT32 i; + INT32 i, j; UINT8 pingame = 0, pexiting = 0; @@ -624,12 +690,17 @@ void K_KartHandleShieldCooldown(SINT8 item) if (((shieldtype == K_GetShieldFromItem(players[i].itemtype)) || (shieldtype == K_GetShieldFromPlayer(&players[i])))) { - // If this shield has a cooldown, force-apply the cooldown preeemptively for - // the entire time the shield is being held by a player. - if (K_GetBGone(item, true) > 0) + for (j = 0; j < numkartresults; j++) { - K_SetBGoneToBase(item); - break; + kartresult_t *result = &kartresults[j]; + + // If this shield has a cooldown, force-apply the cooldown preeemptively for + // the entire time the shield is being held by a player. + if (result->type == item && result->basebgone > 0) + { + result->bgone = result->basebgone * TICRATE; + break; + } } } } @@ -643,7 +714,7 @@ void K_KartHandleShieldCooldown(SINT8 item) */ INT32 K_KartGetItemOdds( - UINT8 pos, SINT8 item, + UINT8 pos, const kartresult_t *result, UINT32 ourDist, UINT32 clusterDist, fixed_t mashed, @@ -658,22 +729,11 @@ INT32 K_KartGetItemOdds( UINT32 firstDist = UINT32_MAX; UINT32 secondToFirst = UINT32_MAX; - boolean powerItem = false; - boolean cooldownOnStart = false; - boolean indirectItem = false; - boolean notNearEnd = false; - boolean notForBottom = false; + UINT8 flags = result->flags; INT32 shieldtype = KSHIELD_NONE; - I_Assert(item > KITEM_NONE); // too many off by one scenarioes. - I_Assert(KartItemCVars[NUMBASEKARTRESULTS-2] != NULL); // Make sure this exists - - // Alt. item definitions are literally only for odds tables and cooldowns. - // Don't let the actual item listing step out of that boundary. - item = CLAMP(item, 0, NUMBASEKARTRESULTS); - - if (!KartItemCVars[item-1]->value && !modeattacking) + if (!K_ItemResultEnabled(result->name) && !modeattacking) return 0; /* @@ -697,28 +757,27 @@ INT32 K_KartGetItemOdds( INT32 oddsmul = BASEODDSMUL; // Item type used for actual odds retrieval and cooldown assignments. - SINT8 useitem = K_GetAlternateVersion(item); + UINT8 oddstable; if (gametyperules & GTR_BATTLEODDS) - { - I_Assert(pos < 2); // DO NOT allow positions past the bounds of the table - newodds = K_KartItemOddsBattle[useitem-1][pos]; - oddsmul = BATTLEODDSMUL; - } + oddstable = ODDS_BATTLE; else if (gametyperules & GTR_RACEODDS) - { - I_Assert(pos < MAXODDS); // Ditto - newodds = K_KartItemOddsRace[useitem-1][pos]; - } + oddstable = ODDS_RACE; else - { - newodds = 0; - } + oddstable = ODDS_SPECIAL; + + I_Assert(pos < oddstablelen[oddstable]); // DO NOT allow positions past the bounds of the table + + if (gametyperules & GTR_BATTLEODDS) + oddsmul = BATTLEODDSMUL; + + // TODO: braaap (make a separate table for the current level!) + newodds = result->odds[oddstable][pos]; // Blow up the odds with a multiplier. newodds *= oddsmul; - shieldtype = K_GetShieldFromItem(item); + shieldtype = K_GetShieldFromItem(result->type); for (i = 0; i < MAXPLAYERS; i++) { @@ -781,72 +840,36 @@ INT32 K_KartGetItemOdds( } } - switch (item) + switch (result->type) { - case KITEM_BANANA: - notNearEnd = true; - notForBottom = true; - break; case KITEM_EGGMAN: if (K_IsKartItemAlternate(KITEM_EGGMAN)) - { - notForBottom = true; - } - else - { - // It blows you up and is overall ridiculous. This was *overdue*. - cooldownOnStart = true; - powerItem = true; - - notNearEnd = true; - notForBottom = true; - } + flags = KRF_NOTFORBOTTOM; break; - case KITEM_SUPERRING: - notNearEnd = true; - notForBottom = true; + case KITEM_SUPERRING: if ((K_RingsActive() == false)) // No rings rolled if rings are turned off. { newodds = 0; } break; + case KITEM_LANDMINE: // au revoir newodds = 0; break; - case KITEM_ROCKETSNEAKER: - case KRITEM_TRIPLESNEAKER: - powerItem = true; - break; - case KITEM_BUBBLESHIELD: - // Experiment: Given the refactoring of the item, remove it from the cooldown pool. - // Also: a given. - case KITEM_BALLHOG: - case KITEM_JAWZ: - case KRITEM_DUALJAWZ: - case KRITEM_TRIPLEORBINAUT: - case KRITEM_QUADORBINAUT: - notForBottom = true; - powerItem = true; - break; - case KRITEM_TRIPLEBANANA: - case KRITEM_TENFOLDBANANA: - powerItem = true; - notForBottom = true; - notNearEnd = true; - break; + case KITEM_INVINCIBILITY: if ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (gametyperules & GTR_RACEODDS)) { // It's a power item, yes, but we don't want mashing to lessen // its chances, so we lie to the game's face. // Nonetheless, apply the start cooldown. - cooldownOnStart = true; + flags = KRF_COOLDOWNONSTART; // Also, PLEASE prevent shitty last lap bagging endings. - notNearEnd = true; + flags |= KRF_NOTNEAREND; // Unique odds for Invincibility. newodds = K_KartGetInvincibilityOdds(clusterDist); @@ -855,24 +878,14 @@ INT32 K_KartGetItemOdds( // finishes, remove the cooldown flag. if (newodds >= INVFORCEODDS) { - cooldownOnStart = false; + flags &= ~KRF_COOLDOWNONSTART; } - + newodds *= BASEODDSMUL; break; } - /*FALLTHRU*/ - case KITEM_MINE: - case KITEM_GROW: - case KITEM_FLAMESHIELD: - cooldownOnStart = true; - powerItem = true; - break; - case KITEM_SPB: - cooldownOnStart = true; - indirectItem = true; - notNearEnd = true; + case KITEM_SPB: if (!K_LegacyOddsMode() && firstDist < (UINT32)ENDDIST) // No SPB near the end of the race { newodds = 0; @@ -897,17 +910,11 @@ INT32 K_KartGetItemOdds( newodds *= multiplier; } break; + case KITEM_SHRINK: - cooldownOnStart = true; - powerItem = true; - - // "Why keep this for Alt. Shrink?" Bag. Ging. - // ESPECIALLY with double items. - notNearEnd = true; - if (!K_IsKartItemAlternate(KITEM_SHRINK)) { - indirectItem = true; + flags |= KRF_INDIRECTITEM; if (pingame-1 <= pexiting) newodds = 0; @@ -922,15 +929,9 @@ INT32 K_KartGetItemOdds( } break; case KITEM_THUNDERSHIELD: - cooldownOnStart = true; - powerItem = true; - if (spbplace != -1) newodds = 0; break; - case KITEM_HYUDORO: - cooldownOnStart = true; - break; default: break; } @@ -938,7 +939,7 @@ INT32 K_KartGetItemOdds( // In very small matches, remove the stupid bottom half item limiter if (pingame < 6) { - notForBottom = false; + flags &= ~KRF_NOTFORBOTTOM; } if (newodds == 0) @@ -947,32 +948,32 @@ INT32 K_KartGetItemOdds( return newodds; } - if (K_GetBGone(useitem, false) > 0) + if (result->bgone > 0) { // (Replaces hyubgone) This item is on cooldown; don't let it get rolled. newodds = 0; } - else if ((indirectItem == true) && (indirectitemcooldown > 0)) + else if (flags & KRF_INDIRECTITEM && indirectitemcooldown > 0) { // Too many items that act indirectly in a match can feel kind of bad. newodds = 0; } - else if ((cooldownOnStart == true) && (leveltime < (30*TICRATE)+starttime)) + else if (flags & KRF_COOLDOWNONSTART && leveltime < (30*TICRATE)+starttime) { // This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items) newodds = 0; } - else if (!K_LegacyOddsMode() && (notNearEnd == true) && (ourDist < (UINT32)ENDDIST)) + else if (!K_LegacyOddsMode() && flags & KRF_NOTNEAREND && ourDist < (UINT32)ENDDIST) { // This item should not appear at the end of a race. (Usually trap items that lose their effectiveness) newodds = 0; } - else if ((notForBottom == true) && (inBottom == true) && (leveltime >= (30*TICRATE)+starttime)) + else if (flags & KRF_NOTFORBOTTOM && inBottom && leveltime >= (30*TICRATE)+starttime) { // This item should not appear for losing players. (Usually items that feel less effective at these positions) newodds = 0; } - else if (powerItem == true) + else if (flags & KRF_POWERITEM) { // This item is a "power item". This activates "frantic item" toggle related functionality. fixed_t fracOdds = newodds * FRACUNIT; @@ -1036,10 +1037,10 @@ UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 b break; } - for (j = 1; j < NUMBASEKARTRESULTS; j++) + for (j = 0; j < numkartresults; j++) { if (K_KartGetItemOdds( - i, j, + i, &kartresults[j], player->distancetofinish, player->distancefromcluster, mashed, @@ -1150,43 +1151,37 @@ UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 b INT32 K_GetRollingRouletteItem(player_t *player) { - static UINT8 translation[NUMKARTITEMS-1]; + static UINT8 translation[MAXKARTRESULTS]; static UINT16 roulette_size; static INT16 odds_cached = -1; // Race odds have more columns than Battle - const UINT8 EMPTYODDS[sizeof K_KartItemOddsRace[0]] = {0}; + const UINT8 EMPTYODDS[MAXODDS] = {0}; // or not if (odds_cached != gametype) { - UINT8 *odds_row; - size_t odds_row_size; - - UINT8 i; + UINT8 oddstable = 0; + kartitemtype_e seen[MAXKARTITEMS]; + size_t numseen = 0, j; roulette_size = 0; if (gametyperules & GTR_BATTLEODDS) - { - odds_row = K_KartItemOddsBattle[0]; - odds_row_size = sizeof K_KartItemOddsBattle[0]; - } + oddstable = ODDS_BATTLE; else - { - odds_row = K_KartItemOddsRace[0]; - odds_row_size = sizeof K_KartItemOddsRace[0]; - } + oddstable = ODDS_RACE; - for (i = 1; i < NUMKARTITEMS; ++i) + for (UINT8 i = 0; i < numkartresults; i++) { - if (memcmp(odds_row, EMPTYODDS, odds_row_size)) - { - translation[roulette_size] = i; - roulette_size++; - } + kartresult_t *result = &kartresults[i]; - odds_row += odds_row_size; + for (j = 0; j < numseen; j++) + if (seen[j] == result->type) + break; + + if (j == numseen && memcmp(result->odds[oddstable], EMPTYODDS, sizeof(EMPTYODDS))) + translation[roulette_size++] = seen[numseen++] = result->type; } roulette_size *= 3; @@ -1423,7 +1418,7 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) UINT8 roulettestop; UINT32 pdis = 0; UINT8 useodds = 0; - INT32 spawnchance[NUMBASEKARTRESULTS]; + INT32 spawnchance[MAXKARTRESULTS]; INT64 totalspawnchance = 0; // 75-scale numbers are going to get BIG. This is for paranoia's sake. UINT8 bestbumper = 0; fixed_t mashed = 0; @@ -1497,7 +1492,8 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // Give a debug item instead if specified if (cv_kartdebugitem.value != 0 && !modeattacking) { - K_KartGetItemResult(player, cv_kartdebugitem.value); + player->itemtype = cv_kartdebugitem.value; + player->itemamount = cv_kartdebugamount.value; player->itemblink = TICRATE; player->itemblinkmode = KITEMBLINKMODE_KARMA; player->itemroulette = KROULETTE_DISABLED; @@ -1511,9 +1507,9 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // This Gametype never specified an odds type. Roll something random please! if (!(gametyperules & GTR_RACEODDS) && !(gametyperules & GTR_BATTLEODDS)) { - SINT8 itemroll = P_RandomRange(KITEM_SNEAKER, NUMKARTITEMS - 1); + UINT8 itemroll = P_RandomRange(0, numkartresults - 1); - K_KartGetItemResult(player, itemroll); + K_KartGetItemResult(player, kartresults[itemroll].name); player->itemblink = TICRATE; player->itemblinkmode = KITEMBLINKMODE_NORMAL; player->itemroulette = KROULETTE_DISABLED; @@ -1531,19 +1527,19 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { if ((gametyperules & GTR_RACEODDS)) { - if (mashed && ((K_RingsActive() == true) && (modeattacking || cv_superring.value))) // ANY mashed value? You get rings. + if (mashed && K_RingsActive() && (modeattacking || K_ItemResultEnabled("superring"))) // ANY mashed value? You get rings. { - K_KartGetItemResult(player, KITEM_SUPERRING); + K_KartGetItemResult(player, "superring"); player->itemblinkmode = KITEMBLINKMODE_MASHED; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); } else { - if (modeattacking || cv_sneaker.value) // Waited patiently? You get a sneaker! - K_KartGetItemResult(player, KITEM_SNEAKER); + if (modeattacking || K_ItemResultEnabled("sneaker")) // Waited patiently? You get a sneaker! + K_KartGetItemResult(player, "sneaker"); else // Default to sad if nothing's enabled... - K_KartGetItemResult(player, KITEM_SAD); + K_KartGetItemResult(player, ""); player->itemblinkmode = KITEMBLINKMODE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); @@ -1551,23 +1547,23 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } else if (gametyperules & GTR_BATTLEODDS) { - if (mashed && (bossinfo.boss || cv_banana.value) && !itembreaker) // ANY mashed value? You get a banana. + if (mashed && (bossinfo.boss || K_ItemResultEnabled("banana")) && !itembreaker) // ANY mashed value? You get a banana. { - K_KartGetItemResult(player, KITEM_BANANA); + K_KartGetItemResult(player, "banana"); player->itemblinkmode = KITEMBLINKMODE_MASHED; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); } else if (bossinfo.boss) { - K_KartGetItemResult(player, KITEM_ORBINAUT); + K_KartGetItemResult(player, "orbinaut"); player->itemblinkmode = KITEMBLINKMODE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); } else if (itembreaker) { - K_KartGetItemResult(player, KITEM_SNEAKER); + K_KartGetItemResult(player, "sneaker"); player->itemblinkmode = KITEMBLINKMODE_MASHED; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); @@ -1582,12 +1578,12 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // SPECIAL CASE No. 5: // Being in ring debt occasionally forces Super Ring on you if you mashed - if ((K_RingsActive() == true) && mashed && player->rings < 0 && cv_superring.value) + if (K_RingsActive() && mashed && player->rings < 0 && K_ItemResultEnabled("superring")) { INT32 debtamount = min(abs(player->ringmin), abs(player->rings)); if (P_RandomChance((debtamount*FRACUNIT)/abs(player->ringmin))) { - K_KartGetItemResult(player, KITEM_SUPERRING); + K_KartGetItemResult(player, "superring"); player->itemblink = TICRATE; player->itemblinkmode = KITEMBLINKMODE_MASHED; player->itemroulette = KROULETTE_DISABLED; @@ -1603,9 +1599,9 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // In battle, an SPB is forced onto players to target the "most wanted" player if (K_CanForceSPB(player, pdis) && spbplace == -1 && !indirectitemcooldown && !dontforcespb - && cv_selfpropelledbomb.value) + && K_ItemResultEnabled("spb")) { - K_KartGetItemResult(player, KITEM_SPB); + K_KartGetItemResult(player, "spb"); player->itemblink = TICRATE; player->itemblinkmode = KITEMBLINKMODE_KARMA; player->itemroulette = KROULETTE_DISABLED; @@ -1617,17 +1613,15 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables. // Initializes existing spawnchance values - for (i = 0; i < NUMBASEKARTRESULTS; i++) - spawnchance[i] = 0; + memset(spawnchance, 0, sizeof(spawnchance)); // Split into another function for a debug function below useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush); - for (i = 1; i < NUMBASEKARTRESULTS; i++) + for (i = 0; i < numkartresults; i++) { - spawnchance[i] = (totalspawnchance += K_KartGetItemOdds( - useodds, i, + useodds, &kartresults[i], player->distancetofinish, player->distancefromcluster, mashed, @@ -1642,14 +1636,13 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (totalspawnchance > 0) { totalspawnchance = P_RandomKey(totalspawnchance); - for (i = 0; i < NUMBASEKARTRESULTS && spawnchance[i] <= totalspawnchance; i++); + for (i = 0; i < numkartresults && spawnchance[i] <= totalspawnchance; i++); - K_KartGetItemResult(player, i); + K_KartGetItemResult(player, kartresults[i].name); } else { - player->itemtype = KITEM_SAD; - player->itemamount = 1; + K_KartGetItemResult(player, ""); } if (P_IsDisplayPlayer(player)) @@ -1661,3 +1654,76 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) player->itemroulette = KROULETTE_DISABLED; // Since we're done, clear the roulette number player->roulettetype = KROULETTETYPE_NORMAL; // This too } + +/** \brief Returns true or false if the player is shrunk. + + \param player (player_t) Player to test shrunken status for + + \return Is this player shrunk? +*/ +boolean K_IsShrunk(const player_t *player) +{ + return (player->growshrinktimer < 0); +} + +INT16 K_GetShrinkTime(player_t *player) +{ + return (player->growshrinktimer * -1); +} + +fixed_t K_AccomodateShrinkScaling(fixed_t x) +{ + return FixedDiv(x, SHRINK_SCALE); +} + +/** \brief Depending on the Shrink type set, this returns true or false if the player is shrunk. + + \param player (player_t) Player to test shrunken status for + \param legacy (boolean) Legacy shrink? + + \return void +*/ +boolean K_IsShrunkMode(const player_t *player, boolean legacy) +{ + boolean shrunk = K_IsShrunk(player); + boolean legacytype = (!K_IsKartItemAlternate(KITEM_SHRINK)); + + if (legacy) + { + return ((shrunk) && (legacytype)); + } + + return ((shrunk) && (!legacytype)); +} + +#define ALTSHRINK_EPSILON (320 * FRACUNIT) +#define NEIGHBOR_IFRAMES (TICRATE / 2) +#define BASE_IFRAMES (2 * TICRATE) + +void K_AltShrinkIFrames(player_t *player) +{ + vector3_t tempclusterpoint; + + // Find neighbors + INT32 N = K_CountNeighboringPlayers(player, ALTSHRINK_EPSILON, &tempclusterpoint); + + // For every neighbor, add some iframes for a clean breakaway. + player->flashing = (UINT16)min((INT32)(UINT16_MAX), BASE_IFRAMES + (NEIGHBOR_IFRAMES * N)); +} + +#define PITY_SHRINKINCREASE_BASE (3) +#define PITY_SHRINKINCREASE (TICRATE / 2) + +void K_AltShrinkPityIncrease(player_t *player) +{ + // Increase your shrink timer by a little bit for every player you run into. + INT32 shrinktime = (UINT32)(K_GetShrinkTime(player)); + + fixed_t dimin = FRACUNIT; + + dimin = max(0, 5 - player->altshrinktimeshit) * FRACUNIT / 5; + + shrinktime = min(INT16_MAX, shrinktime + PITY_SHRINKINCREASE_BASE + FixedMul(PITY_SHRINKINCREASE, dimin)); + + player->growshrinktimer = ((INT16)shrinktime) * -1; +} diff --git a/src/k_items.h b/src/k_items.h new file mode 100644 index 000000000..d6183a68e --- /dev/null +++ b/src/k_items.h @@ -0,0 +1,147 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2025 by Kart Krew. +// Copyright (C) 2025 by "Anonimus". +// Copyright (C) 2025 Blankart Team. +// +// 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 k_items.h +/// \brief Kart item systems. + +#ifndef __K_ITEMS__ +#define __K_ITEMS__ + +#include "doomdef.h" +#include "doomtype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Max odds count +#define MAXODDS 16 + +// Distance variables +#define DISTVAR CV_Get(&cv_kartoddsdist) +#define DISTVAR_LEGACY CV_Get(&cv_kartlegacyoddsdist) +#define SPBDISTVAR CV_Get(&cv_kartspbdist) +#define SPBDISTVAR_LEGACY CV_Get(&cv_kartlegacyspbdist) + +typedef enum +{ + KITEM_SAD = -1, + KITEM_NONE = 0, + KITEM_SNEAKER, + KITEM_ROCKETSNEAKER, + KITEM_INVINCIBILITY, + KITEM_BANANA, + KITEM_EGGMAN, + KITEM_ORBINAUT, + KITEM_JAWZ, + KITEM_MINE, + KITEM_BALLHOG, + KITEM_SPB, + KITEM_GROW, + KITEM_SHRINK, + KITEM_THUNDERSHIELD, + KITEM_HYUDORO, + KITEM_POGOSPRING, + KITEM_KITCHENSINK, + KITEM_SUPERRING, + KITEM_LANDMINE, + KITEM_BUBBLESHIELD, + KITEM_FLAMESHIELD, + + KITEM_FIRSTFREESLOT, + KITEM_LASTFREESLOT = 126, + MAXKARTITEMS +} ATTRPACK kartitemtype_e; + +#define MAXKARTRESULTS 255 + +typedef enum +{ + ODDS_RACE, + ODDS_BATTLE, + ODDS_SPECIAL, + MAXODDSTABLES +} ATTRPACK kartoddstable_e; + +struct kartitemgraphics_t +{ + UINT8 numpatches; + const char **patchnames; + patch_t **patches; +}; + +struct kartitem_t +{ + const char *name; + consvar_t *altcvar; + kartitemgraphics_t graphics[2]; + boolean animated; + boolean darkbg; +}; + +enum +{ + KRF_INDIRECTITEM = 1<<0, + KRF_POWERITEM = 1<<1, + KRF_COOLDOWNONSTART = 1<<2, + KRF_NOTNEAREND = 1<<3, + KRF_NOTFORBOTTOM = 1<<4, +}; + +struct kartresult_t +{ + const char *name; + consvar_t *cvar; + kartitemtype_e type; + UINT8 amount; + UINT8 odds[MAXODDSTABLES][MAXODDS]; + UINT8 flags; + tic_t basebgone, bgone; +}; + +extern kartitem_t kartitems[MAXKARTITEMS]; +extern UINT8 numkartitems; +extern kartresult_t kartresults[MAXKARTRESULTS]; +extern UINT8 numkartresults; + +kartresult_t *K_GetKartResult(const char *name); +void K_InitializeItems(void); +boolean K_ItemResultEnabled(const char *name); +void K_SetupItemOdds(void); + +void K_KartHandleShieldCooldown(kartitemtype_e item); +boolean K_LegacyOddsMode(void); +UINT32 K_GetCongaLineDistance(const player_t *player, UINT8 startPos); + +UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame); +UINT32 K_CalculatePDIS(const player_t *player, UINT8 numPlayers, boolean *spbrush); +UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush); +UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush); +INT32 K_KartGetItemOdds(UINT8 pos, const kartresult_t *result, UINT32 ourDist, UINT32 clusterDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival, boolean inBottom); +INT32 K_GetRollingRouletteItem(player_t *player); +void K_KartItemRoulette(player_t *player, ticcmd_t *cmd); + +boolean K_IsShrunk(const player_t *player); +INT16 K_GetShrinkTime(player_t *player); +fixed_t K_AccomodateShrinkScaling(fixed_t x); + +boolean K_IsShrunkMode(const player_t *player, boolean legacy); + +#define K_IsLegacyShrunk(player) (K_IsShrunkMode(player, true)) +#define K_IsAltShrunk(player) (K_IsShrunkMode(player, false)) + +void K_AltShrinkIFrames(player_t *player); +void K_AltShrinkPityIncrease(player_t *player); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __K_ITEMS__ diff --git a/src/k_kart.c b/src/k_kart.c index 04f3316af..31f801ec4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -64,9 +64,8 @@ #include "k_follower.h" #include "k_grandprix.h" #include "k_cluster.hpp" -#include "k_odds.h" +#include "k_items.h" #include "k_specialstage.h" -#include "k_altshrink.h" #include "h_timers.h" #include "blan/b_soc.h" @@ -233,37 +232,6 @@ angle_t K_ReflectAngle(angle_t yourangle, angle_t theirangle, fixed_t yourspeed, void K_RegisterKartStuff(void) { - CV_RegisterVar(&cv_sneaker); - CV_RegisterVar(&cv_rocketsneaker); - CV_RegisterVar(&cv_invincibility); - CV_RegisterVar(&cv_banana); - CV_RegisterVar(&cv_eggmanmonitor); - CV_RegisterVar(&cv_orbinaut); - CV_RegisterVar(&cv_jawz); - CV_RegisterVar(&cv_mine); - CV_RegisterVar(&cv_ballhog); - CV_RegisterVar(&cv_selfpropelledbomb); - CV_RegisterVar(&cv_grow); - CV_RegisterVar(&cv_shrink); - CV_RegisterVar(&cv_thundershield); - CV_RegisterVar(&cv_hyudoro); - CV_RegisterVar(&cv_pogospring); - CV_RegisterVar(&cv_kitchensink); - - // Nu-ITEMS - CV_RegisterVar(&cv_superring); - CV_RegisterVar(&cv_landmine); // FIXME: Kill it. - CV_RegisterVar(&cv_bubbleshield); - CV_RegisterVar(&cv_flameshield); - - CV_RegisterVar(&cv_dualsneaker); - CV_RegisterVar(&cv_triplesneaker); - CV_RegisterVar(&cv_triplebanana); - CV_RegisterVar(&cv_decabanana); - CV_RegisterVar(&cv_tripleorbinaut); - CV_RegisterVar(&cv_quadorbinaut); - CV_RegisterVar(&cv_dualjawz); - CV_RegisterVar(&cv_kartminimap); CV_RegisterVar(&cv_kartcheck); CV_RegisterVar(&cv_kartinvinsfx); @@ -289,8 +257,6 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartusepwrlv); CV_RegisterVar(&cv_votetime); - CV_RegisterVar(&cv_kartdebugitem); - CV_RegisterVar(&cv_kartdebugamount); CV_RegisterVar(&cv_kartdebugshrink); CV_RegisterVar(&cv_kartdebugdistribution); CV_RegisterVar(&cv_kartdebughuddrop); @@ -415,10 +381,8 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartslopeboost); - CV_RegisterVar(&cv_kartshrinktype); CV_RegisterVar(&cv_kartaltshrinktime); - CV_RegisterVar(&cv_kartinvintype); CV_RegisterVar(&cv_kartinvindist); CV_RegisterVar(&cv_kartinvindistmul); @@ -4742,7 +4706,7 @@ static void K_DoHyudoroSteal(player_t *player) prandom = P_RandomFixed(); S_StartSound(player->mo, sfx_s3k92); - if (sink && numplayers > 0 && cv_kitchensink.value) // BEHOLD THE KITCHEN SINK + if (sink && numplayers > 0 && K_ItemResultEnabled("kitchensink")) // BEHOLD THE KITCHEN SINK { player->hyudorotimer = hyu; player->stealingtimer = stealtime; @@ -5538,7 +5502,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 if (type == 0) { UINT8 useodds = 0; - INT32 spawnchance[NUMBASEKARTRESULTS]; + INT32 spawnchance[MAXKARTRESULTS]; INT32 totalspawnchance = 0; INT32 i; @@ -5546,10 +5510,10 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 useodds = amount; - for (i = 1; i < NUMBASEKARTRESULTS; i++) + for (i = 0; i < numkartresults; i++) { spawnchance[i] = (totalspawnchance += K_KartGetItemOdds( - useodds, i, + useodds, &kartresults[i], UINT32_MAX, 0, 0, @@ -5561,30 +5525,29 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 if (totalspawnchance > 0) { totalspawnchance = P_RandomKey(totalspawnchance); - for (i = 0; i < NUMBASEKARTRESULTS && spawnchance[i] <= totalspawnchance; i++); + for (i = 0; i < numkartresults && spawnchance[i] <= totalspawnchance; i++); // TODO: this is bad! // K_KartGetItemResult requires a player // but item roulette will need rewritten to change this - const UINT8 newType = K_ItemResultToType(i); - const UINT8 newAmount = K_ItemResultToAmount(i); + const kartresult_t *result = &kartresults[i]; - if (newAmount > 1) + if (result->amount > 1) { UINT8 j; - for (j = 0; j < newAmount-1; j++) + for (j = 0; j < result->amount-1; j++) { K_CreatePaperItem( x, y, z, angle, flip, - newType, 1 + result->type, 1 ); } } - drop->threshold = newType; + drop->threshold = result->type; drop->movecount = 1; } else @@ -11507,30 +11470,10 @@ boolean K_ItemPushingActive(void) return itempushing; } -boolean K_GetKartInvinType(void) -{ - return invintype; -} - boolean K_IsKartItemAlternate(UINT8 itemtype) { - switch (itemtype) - { - case KITEM_INVINCIBILITY: - return invintype == KARTITEM_ALTERN; - break; - case KITEM_EGGMAN: - return eggmantype == KARTITEM_ALTERN; - break; - case KITEM_SHRINK: - return shrinktype == KARTITEM_ALTERN; - break; - - default: - return false; - break; - } - return false; + return itemtype >= 0 && itemtype < numkartitems + && kartitems[itemtype].altcvar != NULL && kartitems[itemtype].altcvar->value == 1; } boolean K_UsingLegacyCheckpoints(void) diff --git a/src/k_kart.h b/src/k_kart.h index e85aae584..d5503cb44 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -126,6 +126,11 @@ extern vector3_t clusterpoint, clusterdtf; #define FLAMEACCELBOOST CV_Get(&cv_kartstacking_flame_accelboost) #define FLAMESTACKABLE CV_Get(&cv_kartstacking_flame_stackable) +#define ALTSHRINKTIME CV_Get(&cv_kartaltshrinktime) +#define SHRINKSPEEDBOOST CV_Get(&cv_kartstacking_altshrink_speedboost) +#define SHRINKACCELBOOST CV_Get(&cv_kartstacking_altshrink_accelboost) +#define SHRINKSTACKABLE CV_Get(&cv_kartstacking_altshrink_stackable) + #define STARTSPEEDBOOST CV_Get(&cv_kartstacking_start_speedboost) #define STARTACCELBOOST CV_Get(&cv_kartstacking_start_accelboost) #define STARTSTACKABLE CV_Get(&cv_kartstacking_start_stackable) @@ -344,7 +349,6 @@ boolean K_DraftingActive(void); boolean K_AirDropActive(void); boolean K_ItemLitterActive(void); boolean K_ItemPushingActive(void); -boolean K_GetKartInvinType(void); boolean K_IsKartItemAlternate(UINT8 itemtype); INT32 K_GetBumpSpark(void); boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound); diff --git a/src/k_odds.h b/src/k_odds.h deleted file mode 100644 index a762f8f0e..000000000 --- a/src/k_odds.h +++ /dev/null @@ -1,72 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -// Copyright (C) 2018-2025 by Kart Krew. -// Copyright (C) 2025 by "Anonimus". -// Copyright (C) 2025 Blankart Team. -// -// 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 k_odds.hpp -/// \brief Kart item odds systems. - -#ifndef __K_ODDS__ -#define __K_ODDS__ - -#include "command.h" // Need for player_t -#include "doomdef.h" -#include "doomtype.h" -#include "d_player.h" // Need for player_t -#include "d_ticcmd.h" -#include "m_fixed.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Max odds count -#define MAXODDS 16 - -// Distance variables -#define DISTVAR CV_Get(&cv_kartoddsdist) -#define DISTVAR_LEGACY CV_Get(&cv_kartlegacyoddsdist) -#define SPBDISTVAR CV_Get(&cv_kartspbdist) -#define SPBDISTVAR_LEGACY CV_Get(&cv_kartlegacyspbdist) - -extern consvar_t *KartItemCVars[NUMKARTRESULTS-1]; - -// Goner; tracks how long an item should be "gone" for. -// AKA a time-based cooldown so Hyudoro and whatever else piss off to prevent -// spamming. - -typedef enum goner_sect_e { - GONER_BASECOOLDOWN = 0, - GONER_CURRCOOLDOWN = 1, -} goner_sect_t; - -extern tic_t ItemBGone[NUMKARTRESULTS][2]; - -void K_SetBGone(SINT8 item, tic_t time); -void K_SetBGoneToBase(SINT8 item); -tic_t K_GetBGone(SINT8 item, boolean base); -void K_KartHandleShieldCooldown(SINT8 item); - -boolean K_LegacyOddsMode(void); -UINT32 K_GetCongaLineDistance(const player_t *player, UINT8 startPos); - -UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame); -UINT32 K_CalculatePDIS(const player_t *player, UINT8 numPlayers, boolean *spbrush); -UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush); -UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush); -INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, UINT32 clusterDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival, boolean inBottom); -INT32 K_GetRollingRouletteItem(player_t *player); -SINT8 K_ItemResultToType(SINT8 getitem); -UINT8 K_ItemResultToAmount(SINT8 getitem); -void K_KartItemRoulette(player_t *player, ticcmd_t *cmd); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // __K_ODDS__ diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9762c280e..9862db465 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -33,7 +33,7 @@ #include "k_color.h" #include "k_hud.h" #include "k_waypoint.h" -#include "k_odds.h" +#include "k_items.h" #include "d_netcmd.h" // IsPlayerAdmin #include "m_menu.h" // Player Setup menu color stuff #include "p_spec.h" // P_StartQuake @@ -4026,10 +4026,20 @@ static int lib_kGetKartFlashing(lua_State *L) static int lib_kGetItemPatch(lua_State *L) { - UINT8 item = (UINT8)luaL_optinteger(L, 1, KITEM_NONE); + kartitemtype_e item = (kartitemtype_e)luaL_optinteger(L, 1, KITEM_NONE); boolean tiny = lua_optboolean(L, 2); //HUDSAFE - lua_pushstring(L, K_GetItemPatch(item, tiny)); + + // TODO: compatmode KRITEM + const char *sad = tiny ? "K_ISSAD" : "K_ITSAD"; + if (item <= 0 || item >= numkartitems) + { + lua_pushstring(L, sad); + return 1; + } + + kartitemgraphics_t *graphics = &kartitems[item].graphics[tiny ? 1 : 0]; + lua_pushstring(L, graphics->numpatches == 0 ? sad : graphics->patchnames[0]); return 1; } @@ -4111,48 +4121,10 @@ static int lib_kSetHyuCountdown(lua_State *L) { tic_t c = (tic_t)luaL_checkinteger(L, 1); NOHUD - K_SetBGone(KITEM_HYUDORO, c); + K_GetKartResult("hyudoro")->bgone = c; return 0; } -static int lib_kSetBGone(lua_State *L) -{ - SINT8 item = (SINT8)luaL_checkinteger(L, 1); - tic_t c = (tic_t)luaL_checkinteger(L, 2); - NOHUD - if (item < KITEM_SNEAKER || item > (NUMKARTRESULTS - 1)) - { - luaL_error(L, "given item ID is outside bgone range"); - } - K_SetBGone(item, c); - return 0; -} - -static int lib_kSetBGoneToBase(lua_State *L) -{ - SINT8 item = (SINT8)luaL_checkinteger(L, 1); - NOHUD - if (item < KITEM_SNEAKER || item > (NUMKARTRESULTS - 1)) - { - luaL_error(L, "given item ID is outside bgone range"); - } - K_SetBGoneToBase(item); - return 0; -} - -static int lib_kGetBGone(lua_State *L) -{ - SINT8 item = (SINT8)luaL_checkinteger(L, 1); - boolean base = lua_isnoneornil(L, 2) ? false : luaL_checkboolean(L, 2); - NOHUD - if (item < KITEM_SNEAKER || item > (NUMKARTRESULTS - 1)) - { - luaL_error(L, "given item ID is outside bgone range"); - } - lua_pushinteger(L, K_GetBGone(item, base)); - return 1; -} - // Checks if the floor closet floor under an object would be safe to respawn/land on. static int lib_kSafeRespawnPosition(lua_State *L) { @@ -4227,13 +4199,6 @@ static int lib_kItemLitterActive(lua_State *L) return 1; } -// Grabs the currently active invintype. -static int lib_kGetKartInvinType(lua_State *L) -{ - lua_pushinteger(L, K_GetKartInvinType()); - return 1; -} - // Gets the currently active bumpspark type. static int lib_kGetBumpSpark(lua_State *L) { @@ -5341,9 +5306,6 @@ static luaL_Reg lib[] = { {"K_SetExitCountdown",lib_kSetExitCountdown}, {"K_SetIndirectItemCooldown",lib_kSetIndirectItemCountdown}, {"K_SetHyudoroCooldown",lib_kSetHyuCountdown}, - {"K_SetBGone", lib_kSetBGone}, - {"K_SetBGoneToBase", lib_kSetBGoneToBase}, - {"K_GetBGone", lib_kGetBGone}, {"K_SafeRespawnPosition",lib_kSafeRespawnPosition}, {"K_GetCollideAngle",lib_kGetCollideAngle}, @@ -5358,7 +5320,6 @@ static luaL_Reg lib[] = { {"K_AirDropActive",lib_kAirDropActive}, {"K_ItemLitterActive",lib_kItemLitterActive}, {"K_GetBumpSpark",lib_kGetBumpSpark}, - {"K_GetKartInvinType",lib_kGetKartInvinType}, {"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints}, {"K_DoBoost",lib_kDoBoost}, {"K_ClearBoost",lib_kClearBoost}, diff --git a/src/lua_script.c b/src/lua_script.c index 5a4136d23..3a63dbe32 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -27,7 +27,7 @@ #include "p_slopes.h" // for P_SlopeById and slopelist #include "p_polyobj.h" // polyobj_t, PolyObjects #include "k_battle.h" -#include "k_odds.h" +#include "k_items.h" #include "k_waypoint.h" #ifdef LUA_ALLOW_BYTECODE #include "d_netfil.h" // for LUA_DumpFile @@ -417,11 +417,8 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"itempushing")) { lua_pushboolean(L, itempushing); // hmm... i think this should be a boolean return 1; - } else if (fastcmp(word,"invintype")) { - lua_pushinteger(L, invintype); - return 1; } else if (fastcmp(word,"hyubgone")) { - lua_pushinteger(L, K_GetBGone(KITEM_HYUDORO, false)); + lua_pushinteger(L, K_GetKartResult("hyudoro")->bgone); return 1; } else if (fastcmp(word,"encoremode")) { lua_pushboolean(L, encoremode); @@ -564,9 +561,7 @@ int LUA_WriteGlobals(lua_State *L, const char *word) else if (fastcmp(word,"indirectitemcooldown")) indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2); else if (fastcmp(word,"hyubgone")) - { - K_SetBGone(KITEM_HYUDORO, (tic_t)luaL_checkinteger(L, 2)); - } + K_GetKartResult("hyudoro")->bgone = (tic_t)luaL_checkinteger(L, 2); else if (fastcmp(word,"starttime")) starttime = (tic_t)luaL_checkinteger(L, 2); else if (fastcmp(word,"introtime")) diff --git a/src/m_menu.c b/src/m_menu.c index baa98c7df..02b8ac739 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -67,7 +67,7 @@ #include "i_sound.h" #include "k_hud.h" // SRB2kart #include "k_kart.h" -#include "k_odds.h" // KartItemCVars +#include "k_items.h" // KartItemCVars #include "k_pwrlv.h" #include "k_stats.h" // SRB2kart #include "d_player.h" // KITEM_ constants @@ -8327,8 +8327,7 @@ void MD_DrawMonitorToggles(void) INT32 leftdraw, rightdraw, totaldraw; INT32 x = currentMenu->x, y = currentMenu->y+(spacing/4); INT32 onx = 0, ony = 0; - consvar_t *cv; - INT32 i, translucent, drawnum; + INT32 i, translucent, drawnum, arg; M_DrawMenuTitle(); @@ -8353,7 +8352,7 @@ void MD_DrawMonitorToggles(void) { INT32 j; - for (j = 0; j < height; j++) + for (j = 0; j < height; j++, y += spacing) { const INT32 thisitem = (i*height)+j; @@ -8364,64 +8363,45 @@ void MD_DrawMonitorToggles(void) { onx = x; ony = y; - y += spacing; continue; } -#ifdef ITEMTOGGLEBOTTOMRIGHT - if (currentMenu->menuitems[thisitem].argument == 255) + arg = currentMenu->menuitems[thisitem].argument; + if (arg == 255) { V_DrawScaledPatch(x, y, V_TRANSLUCENT, W_CachePatchName("K_ISBG", PU_CACHE)); continue; } -#endif - if (currentMenu->menuitems[thisitem].argument == 0) + else if (arg == 0) { V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE)); V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISTOGL", PU_CACHE)); continue; } - - cv = KartItemCVars[currentMenu->menuitems[thisitem].argument-1]; - translucent = (cv->value ? 0 : V_TRANSLUCENT); - - switch (currentMenu->menuitems[thisitem].argument) + else if (arg <= 0 && arg > numkartresults) { - case KRITEM_DUALSNEAKER: - case KRITEM_DUALJAWZ: - drawnum = 2; - break; - case KRITEM_TRIPLESNEAKER: - case KRITEM_TRIPLEBANANA: - case KRITEM_TRIPLEORBINAUT: - drawnum = 3; - break; - case KRITEM_QUADORBINAUT: - drawnum = 4; - break; - case KRITEM_TENFOLDBANANA: - drawnum = 10; - break; - default: - drawnum = 0; - break; + continue; } - if (cv->value) + kartresult_t *result = &kartresults[arg - 1]; + kartitem_t *item = &kartitems[result->type]; + boolean enabled = K_ItemResultEnabled(result->name); + translucent = enabled ? 0 : V_TRANSLUCENT; + drawnum = item->animated ? 0 : CLAMP(result->amount, 0, item->graphics[1].numpatches - 1); + + if (enabled) V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE)); else V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBGD", PU_CACHE)); - if (drawnum != 0) + if (drawnum > 1) { V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISMUL", PU_CACHE)); - V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].argument, true), PU_CACHE)); + V_DrawScaledPatch(x, y, translucent, K_GetCachedItemPatch(result->type, true, result->amount)); V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|translucent, va("x%d", drawnum)); } else - V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].argument, true), PU_CACHE)); - - y += spacing; + V_DrawScaledPatch(x, y, translucent, K_GetCachedItemPatch(result->type, true, result->amount)); } x += spacing; @@ -8429,8 +8409,8 @@ void MD_DrawMonitorToggles(void) } { -#ifdef ITEMTOGGLEBOTTOMRIGHT - if (currentMenu->menuitems[itemOn].argument == 255) + arg = currentMenu->menuitems[itemOn].argument; + if (arg == 255) { V_DrawScaledPatch(onx-1, ony-2, V_TRANSLUCENT, W_CachePatchName("K_ITBG", PU_CACHE)); if (shitsfree) @@ -8443,46 +8423,43 @@ void MD_DrawMonitorToggles(void) V_DrawScaledPatch(onx-1, ony-2, trans, W_CachePatchName("K_ITFREE", PU_CACHE)); } } - else -#endif - if (currentMenu->menuitems[itemOn].argument == 0) + else if (arg == 0) { V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE)); V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITTOGL", PU_CACHE)); } - else + else if (arg > 0 && arg <= numkartresults) { - cv = KartItemCVars[currentMenu->menuitems[itemOn].argument-1]; - translucent = (cv->value ? 0 : V_TRANSLUCENT); + kartresult_t *result = &kartresults[arg - 1]; + kartitem_t *item = &kartitems[result->type]; + boolean enabled = K_ItemResultEnabled(result->name); + translucent = enabled ? 0 : V_TRANSLUCENT; + drawnum = item->animated ? 0 : CLAMP(result->amount, 0, item->graphics[0].numpatches - 1); - switch (currentMenu->menuitems[itemOn].argument) - { - case KRITEM_TENFOLDBANANA: - drawnum = 10; - break; - default: - drawnum = 0; - break; - } - - if (cv->value) + if (enabled) V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE)); else V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBGD", PU_CACHE)); - if (drawnum != 0) + if (drawnum > 1) { V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITMUL", PU_CACHE)); - V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].argument, false), PU_CACHE)); + V_DrawScaledPatch(onx-1, ony-2, translucent, K_GetCachedItemPatch(result->type, false, result->amount)); V_DrawScaledPatch(onx+27, ony+39, translucent, W_CachePatchName("K_ITX", PU_CACHE)); V_DrawKartString(onx+37, ony+34, translucent, va("%d", drawnum)); } else - V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].argument, false), PU_CACHE)); + V_DrawScaledPatch(onx-1, ony-2, translucent, K_GetCachedItemPatch(result->type, false, result->amount)); + + if (item->altcvar != NULL) + { + translucent = item->altcvar->value == 1 ? 0 : V_TRANSLUCENT; + V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName("K_ALTITM", PU_CACHE)); + } } } - if (shitsfree) + if (renderisnewtic && shitsfree) shitsfree--; V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, MENUCAPS|highlightflags, va("* %s *", currentMenu->menuitems[itemOn].text)); @@ -8493,7 +8470,11 @@ INT32 MR_HandleMonitorToggles(INT32 choice) const INT32 width = 6, height = 4; INT32 column = itemOn/height, row = itemOn%height; INT16 next; - UINT8 i; + + kartresult_t *result = NULL; + INT32 arg = currentMenu->menuitems[itemOn].argument; + if (arg > 0 && arg <= numkartresults) + result = &kartresults[arg - 1]; switch (choice) { @@ -8542,8 +8523,7 @@ INT32 MR_HandleMonitorToggles(INT32 choice) break; case KEY_ENTER: -#ifdef ITEMTOGGLEBOTTOMRIGHT - if (currentMenu->menuitems[itemOn].argument == 255) + if (choice == 255) { //S_StartSound(NULL, sfx_s26d); if (!shitsfree) @@ -8552,29 +8532,34 @@ INT32 MR_HandleMonitorToggles(INT32 choice) S_StartSound(NULL, sfx_itfree); } } - else -#endif - if (currentMenu->menuitems[itemOn].argument == 0) + else if (choice == 0) { - INT32 v = cv_sneaker.value; + INT32 v = K_ItemResultEnabled("sneaker") ? 1 : 0; S_StartSound(NULL, sfx_s1b4); - for (i = 0; i < NUMBASEKARTRESULTS-1; i++) + for (UINT8 i = 0; i < numkartresults; i++) { - if (KartItemCVars[i]->value == v) - CV_AddValue(KartItemCVars[i], 1); + if (kartresults[i].cvar->value == v) + CV_AddValue(kartresults[i].cvar, 1); } } - else + else if (result != NULL) { S_StartSound(NULL, sfx_s1ba); - CV_AddValue(KartItemCVars[currentMenu->menuitems[itemOn].argument-1], 1); + CV_AddValue(result->cvar, 1); + } + break; + + case KEY_BACKSPACE: + if (result != NULL && kartitems[result->type].altcvar != NULL) + { + S_StartSound(NULL, sfx_s3kb7); + CV_AddValue(kartitems[result->type].altcvar, 1); } break; default: return false; } - return true; } diff --git a/src/p_enemy.c b/src/p_enemy.c index af239e4f8..db181750c 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -30,6 +30,7 @@ #include "k_waypoint.h" #include "k_battle.h" #include "k_collide.h" +#include "k_items.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" diff --git a/src/p_inter.c b/src/p_inter.c index 64cf29405..1066319ff 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -39,7 +39,7 @@ #include "k_boss.h" #include "p_spec.h" #include "k_objects.h" -#include "k_odds.h" +#include "k_items.h" #include "acs/interface.h" // CTF player names @@ -1742,7 +1742,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget break; } - if (target->threshold < 1 || target->threshold >= NUMKARTITEMS) // bruh moment prevention + if (target->threshold < 1 || target->threshold >= numkartitems) // bruh moment prevention { player->itemtype = KITEM_SAD; player->itemamount = 1; diff --git a/src/p_mobj.c b/src/p_mobj.c index 599ddf2ea..fe4ffc362 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -50,7 +50,7 @@ #include "k_terrain.h" #include "k_collide.h" #include "k_objects.h" -#include "k_odds.h" +#include "k_items.h" #include "k_waypoint.h" // BlanKart @@ -4166,7 +4166,7 @@ static void P_RefreshItemCapsuleParts(mobj_t *mobj) mobj_t *part; UINT32 newRenderFlags = 0; - if (itemType < 1 || itemType >= NUMKARTITEMS) + if (itemType < 1 || itemType >= numkartitems) itemType = KITEM_SAD; part = mobj; @@ -11385,7 +11385,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) else if (P_RandomChance(FRACUNIT/3)) mobj->threshold = KITEM_ORBINAUT; else - mobj->threshold = P_RandomRange(1, NUMKARTITEMS - 1); + mobj->threshold = P_RandomRange(1, numkartitems - 1); mobj->movecount = P_RandomChance(FRACUNIT/3) ? 1 : P_RandomKey(32) + 1; #else mobj->threshold = KITEM_SUPERRING; // default item is super ring @@ -12807,7 +12807,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) } case MT_ITEMCAPSULE: { - boolean isRingCapsule = (mthing->args[0] < 1 || mthing->args[0] == KITEM_SUPERRING || mthing->args[0] >= NUMKARTITEMS); + boolean isRingCapsule = mthing->args[0] < 1 || mthing->args[0] == KITEM_SUPERRING || mthing->args[0] >= numkartitems; // don't spawn ring capsules in with rings off. if (isRingCapsule && (K_RingsActive() == false)) @@ -13666,7 +13666,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->flags |= MF_NOGRAVITY; // Angle = item type - if (mthing->args[0] > 0 && mthing->args[0] < NUMKARTITEMS) + if (mthing->args[0] > 0 && mthing->args[0] < numkartitems) mobj->threshold = mthing->args[0]; // Parameter = extra items (x5 for rings) diff --git a/src/p_saveg.c b/src/p_saveg.c index 92982a02b..9ed9194e5 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -41,11 +41,10 @@ #include "k_battle.h" #include "k_pwrlv.h" #include "k_terrain.h" -#include "k_odds.h" +#include "k_items.h" #include "acs/interface.h" #include "g_party.h" #include "k_waypoint.h" -#include "k_altshrink.h" #include @@ -4099,8 +4098,6 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending) SYNCBOOLEAN(itemlittering); SYNCBOOLEAN(itempushing); SYNC(bumpsparkactive); - SYNC(invintype); - SYNC(shrinktype); SYNC(antibumptime); for (i = 0; i < sizeof(votelevels)/sizeof(*votelevels); i++) @@ -4187,11 +4184,11 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending) SYNC(wantedcalcdelay); SYNC(indirectitemcooldown); - for (i = 0; i < NUMKARTRESULTS; i++) + for (i = 0; i < numkartresults; i++) { // hyubgone - //SYNC(ItemBGone[i][GONER_BASECOOLDOWN]); - SYNC(ItemBGone[i][GONER_CURRCOOLDOWN]); + //SYNC(kartresults[i].basebgone); + SYNC(kartresults[i].bgone); } SYNC(mapreset); diff --git a/src/p_setup.c b/src/p_setup.c index 99376d695..75b01c62e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -103,13 +103,12 @@ #include "k_terrain.h" // TRF_TRIPWIRE #include "k_brightmap.h" #include "k_director.h" // K_InitDirector -#include "k_odds.h" // ItemBGone +#include "k_items.h" #include "acs/interface.h" #include "doomstat.h" // MAXMUSNAMES #include "k_mapuser.h" #include "p_deepcopy.h" #include "k_specialstage.h" -#include "k_altshrink.h" #include "blan/b_soc.h" @@ -8072,11 +8071,12 @@ static void P_InitLevelSettings(boolean reloadinggamestate) itempushing = true; bumpsparkactive = (UINT8)cv_kartbumpspark.value; - invintype = (UINT8)cv_kartinvintype.value; - K_UpdateShrinkType(); antibumptime = (tic_t)cv_kartantibump.value * TICRATE; + if (!reloadinggamestate) + K_SetupItemOdds(); + // emerald hunt hunt1 = hunt2 = hunt3 = NULL; @@ -8402,10 +8402,10 @@ static void P_InitGametype(void) wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; - for (i = 0; i < NUMKARTRESULTS; i++) + for (i = 0; i < numkartresults; i++) { // hyubgone - ItemBGone[i][GONER_CURRCOOLDOWN] = 0; + kartresults[i].bgone = 0; } mapreset = 0; diff --git a/src/p_spec.c b/src/p_spec.c index e0a7f990f..0f1506a67 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -44,7 +44,7 @@ // SRB2kart #include "k_kart.h" -#include "k_altshrink.h" +#include "k_items.h" #include "console.h" // CON_LogMessage #include "k_terrain.h" #include "acs/interface.h" diff --git a/src/p_tick.c b/src/p_tick.c index d08fcce92..9733f5b07 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -41,7 +41,7 @@ #include "k_director.h" #include "acs/interface.h" #include "k_bot.h" // K_BotTicker -#include "k_odds.h" // ItemBGone +#include "k_items.h" // ItemBGone #include "k_specialstage.h" #ifdef PARANOIA @@ -902,13 +902,11 @@ void P_Ticker(boolean run) if (indirectitemcooldown > 0) indirectitemcooldown--; - for (i = 0; i < NUMKARTRESULTS; i++) + for (i = 0; i < numkartresults; i++) { // hyubgone - if (K_GetBGone(i, false) > 0) - { - ItemBGone[i][GONER_CURRCOOLDOWN]--; - } + if (kartresults[i].bgone > 0) + kartresults[i].bgone--; } if (gametyperules & GTR_RACEODDS) diff --git a/src/p_user.c b/src/p_user.c index fb45513a9..1aac175f2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -61,8 +61,7 @@ #include "k_terrain.h" // K_SpawnSplashForMobj #include "k_color.h" #include "k_follower.h" -#include "k_odds.h" -#include "k_altshrink.h" +#include "k_items.h" #include "g_party.h" #include "acs/interface.h" diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index 607a8afe4..1623fb2f5 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -18,6 +18,7 @@ #include "p_tick.h" #include "typedef.h" #include "r_fps.h" +#include "k_items.h" #ifdef ROTSPRITE fixed_t rollcosang[ROTANGLES]; diff --git a/src/typedef.h b/src/typedef.h index 9db777746..7d0d3dab7 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -208,6 +208,11 @@ TYPEDEF (waypoint_t); TYPEDEF (mapUserProperty_t); TYPEDEF (mapUserProperties_t); +// k_items.h +TYPEDEF (kartitem_t); +TYPEDEF (kartresult_t); +TYPEDEF (kartitemgraphics_t); + // lua_hudlib_drawlist.h typedef struct huddrawlist_s *huddrawlist_h;