diff --git a/src/d_player.h b/src/d_player.h index e9b237166..306dadb2f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -652,7 +652,8 @@ struct player_t UINT8 ringdelay; // (0 to 3) - 3 tic delay between every ring usage UINT16 ringboost; // Ring boost timer UINT8 sparkleanim; // (0 to 19) - Angle offset for ring sparkle animation - UINT16 superring; // Spawn rings on top of you every tic! + UINT16 superring; // You were awarded rings, and have this many of them left to spawn on yourself. + UINT8 nextringaward; // When should we spawn our next superring ring? UINT8 curshield; // see kartshields_t UINT8 bubblecool; // Bubble Shield use cooldown diff --git a/src/k_hud.c b/src/k_hud.c index 02e6c3b74..7630f52a0 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1636,6 +1636,25 @@ static void K_drawKartSlotMachine(void) return; } + if (stplyr->karthud[khud_itemblink] && (leveltime & 1)) + { + colormode[1] = TC_BLINK; + localcolor[1] = SKINCOLOR_WHITE; + + // This looks kinda wild with the white-background patch. + /* + switch (stplyr->ringboxaward) + { + case 5: // JACKPOT! + localcolor[1] = K_RainbowColor(leveltime); + break; + default: + localcolor[1] = SKINCOLOR_WHITE; + break; + } + */ + } + // pain and suffering defined below if (offset) { diff --git a/src/k_kart.c b/src/k_kart.c index e5b9daec2..718563c7a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1839,7 +1839,10 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top) else { fast->angle = K_MomentumAngle(player->mo); - + if (player->ringboost) + { + P_SetScale(fast, fast->scale + (fast->scale / 300 * player->ringboost)); + } if (player->tripwireLeniency) { fast->destscale = fast->destscale * 2; @@ -1887,6 +1890,17 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top) fast->color = SKINCOLOR_WHITE; fast->colorized = true; } + else if (player->ringboost) + { + UINT8 ringboostcolors[] = {SKINCOLOR_AQUAMARINE, SKINCOLOR_EMERALD, SKINCOLOR_GARDEN, SKINCOLOR_CROCODILE, SKINCOLOR_BANANA}; + UINT8 ringboostbreakpoint = min(player->ringboost / TICRATE / 3, sizeof(ringboostcolors) / sizeof(ringboostcolors[0])); + if (ringboostbreakpoint > 0) + { + fast->color = ringboostcolors[ringboostbreakpoint - 1]; + fast->colorized = true; + fast->renderflags |= RF_ADD; + } + } } void K_SpawnNormalSpeedLines(player_t *player) @@ -3264,7 +3278,9 @@ static void K_GetKartBoostPower(player_t *player) if (player->ringboost) // Ring Boost { - ADDBOOST(FRACUNIT/4, 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling + // This one's a little special: we add extra top speed per tic of ringboost stored up, to allow for Ring Box to really rocket away. + // (We compensate when decrementing ringboost to avoid runaway exponential scaling hell.) + ADDBOOST(FRACUNIT/4 + (FRACUNIT / 2000 * (player->ringboost)), 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling } if (player->eggmanexplode) // Ready-to-explode @@ -3633,14 +3649,14 @@ void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload) if (!overload) { INT32 totalrings = - RINGTOTAL(player) + (player->superring / 3); + RINGTOTAL(player) + (player->superring); /* capped at 20 rings */ if ((totalrings + rings) > 20) rings = (20 - totalrings); } - superring = player->superring + (rings * 3); + superring = player->superring + rings; /* check if not overflow */ if (superring > player->superring) @@ -7997,6 +8013,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) else if (player->ringboost) player->ringboost--; + // These values can get FUCKED ever since ring-stacking speed changes. + // If we're not activetly being awarded rings, roll off extreme ringboost durations. + if (player->superring == 0) + player->ringboost -= (player->ringboost / TICRATE / 2); + if (player->sneakertimer) { player->sneakertimer--; @@ -8107,17 +8128,24 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->superring) { - if (player->superring % 3 == 0) + player->nextringaward++; + UINT8 ringrate = 3 - min(2, player->superring / 20); // Used to consume fat stacks of cash faster. + if (player->nextringaward >= ringrate) { mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); ring->extravalue1 = 1; // Ring collect animation timer ring->angle = player->mo->angle; // animation angle P_SetTarget(&ring->target, player->mo); // toucher for thinker player->pickuprings++; - if (player->superring <= 3) + if (player->superring == 1) ring->cvmem = 1; // play caching when collected + player->nextringaward = 0; + player->superring--; } - player->superring--; + } + else + { + player->nextringaward = 99; // Next time we need to award superring, spawn the first one instantly. } if (player->pflags & PF_VOID) // Returning from FAULT VOID diff --git a/src/k_roulette.c b/src/k_roulette.c index 9e065c81f..f7b1b9ed3 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -229,6 +229,16 @@ static kartslotmachine_t K_KartItemReelRingBox[] = KSM__MAX }; +static sfxenum_t ringboxsound[] = +{ + sfx_slot00, + sfx_slot01, + sfx_slot02, + sfx_slot03, + sfx_slot04, + sfx_slot05 +}; + /*-------------------------------------------------- boolean K_ItemEnabled(kartitems_t item) @@ -1631,7 +1641,12 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd) if (P_IsDisplayPlayer(player) && !demo.freecam) { if (roulette->ringbox) - S_StartSound(NULL, sfx_s245); + { + // Hi modders! Boost your treble and Loudness Normalize to 0 LUFS. + // I'm a responsible audio engineer. -Tyron 2023-07-30 + UINT8 volume = (finalItem > 2) ? (15 * finalItem + 60) : 80; + S_StartSoundAtVolume(NULL, ringboxsound[finalItem], volume); + } else S_StartSound(NULL, sfx_itrolf); } diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 9e7253e97..c25ba71ae 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -353,6 +353,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->sparkleanim); else if (fastcmp(field,"superring")) lua_pushinteger(L, plr->superring); + else if (fastcmp(field,"nextringaward")) + lua_pushinteger(L, plr->nextringaward); else if (fastcmp(field,"curshield")) lua_pushinteger(L, plr->curshield); else if (fastcmp(field,"bubblecool")) @@ -761,6 +763,8 @@ static int player_set(lua_State *L) plr->sparkleanim = luaL_checkinteger(L, 3); else if (fastcmp(field,"superring")) plr->superring = luaL_checkinteger(L, 3); + else if (fastcmp(field,"nextringaward")) + plr->nextringaward = luaL_checkinteger(L, 3); else if (fastcmp(field,"curshield")) plr->curshield = luaL_checkinteger(L, 3); else if (fastcmp(field,"bubblecool")) diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index 9558b81af..8ee063986 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -70,6 +70,13 @@ spawn_debris // Pass down color to dust particles debris->color = config->origin->color; + + if (config->origin->type != MT_RANDOMITEM + || config->origin->extravalue1 < RINGBOX_TIME) + { + debris->color = SKINCOLOR_WHITE; + debris->colorized = true; + } } static void diff --git a/src/p_inter.c b/src/p_inter.c index a358184c9..e779150cc 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -205,6 +205,8 @@ static void P_ItemPop(mobj_t *actor) } */ + Obj_SpawnItemDebrisEffects(actor, actor->target); + P_SetMobjState(actor, S_RINGBOX1); actor->extravalue1 = 0; @@ -217,8 +219,6 @@ static void P_ItemPop(mobj_t *actor) actor->color = SKINCOLOR_GREY; actor->colorized = true; - Obj_SpawnItemDebrisEffects(actor, actor->target); - /* if (locvar1 == 1) { diff --git a/src/p_saveg.c b/src/p_saveg.c index c3db1351f..537a24dae 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -462,6 +462,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT16(save->p, players[i].ringboost); WRITEUINT8(save->p, players[i].sparkleanim); WRITEUINT16(save->p, players[i].superring); + WRITEUINT8(save->p, players[i].nextringaward); WRITEUINT8(save->p, players[i].curshield); WRITEUINT8(save->p, players[i].bubblecool); @@ -883,6 +884,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].ringboost = READUINT16(save->p); players[i].sparkleanim = READUINT8(save->p); players[i].superring = READUINT16(save->p); + players[i].nextringaward = READUINT8(save->p); players[i].curshield = READUINT8(save->p); players[i].bubblecool = READUINT8(save->p); diff --git a/src/sounds.c b/src/sounds.c index ee245babb..7e8560eb2 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1105,6 +1105,14 @@ sfxinfo_t S_sfx[NUMSFX] = {"gpmetr", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // End of a "Tutorial Teleport" {"endwrp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // End of a "Tutorial Teleport" + // SRB2Kart - Ring Box + {"slot00", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bar"}, + {"slot01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Double Bar"}, + {"slot02", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Triple Bar"}, + {"slot03", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Slot Ring"}, + {"slot04", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Seven"}, + {"slot05", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "JACKPOT!"}, + // SRB2Kart - Drop target sounds {"kdtrg1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Low energy, SF_X8AWAYSOUND {"kdtrg2", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Medium energy, SF_X8AWAYSOUND diff --git a/src/sounds.h b/src/sounds.h index a91cfd06f..324066ac9 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1172,6 +1172,14 @@ typedef enum sfx_gpmetr, sfx_endwrp, + // SRB2Kart - Ring Box + sfx_slot00, + sfx_slot01, + sfx_slot02, + sfx_slot03, + sfx_slot04, + sfx_slot05, + // SRB2Kart - Drop target sounds sfx_kdtrg1, sfx_kdtrg2,