From 199a92ebb2e3a9e7049a6b765f00864997b8bd20 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 22 Jul 2024 02:14:11 -0700 Subject: [PATCH] WIP: Overdrive --- src/d_player.h | 7 ++ src/deh_tables.c | 4 + src/info.c | 30 ++++++++ src/info.h | 6 ++ src/k_collide.cpp | 6 ++ src/k_hud.cpp | 66 +++++++++++++++- src/k_kart.c | 151 ++++++++++++++++++++++++++++++++++++- src/k_kart.h | 5 ++ src/k_objects.h | 4 +- src/lua_playerlib.c | 20 +++++ src/objects/CMakeLists.txt | 1 + src/objects/amps.c | 80 ++++++++++++++++++++ src/p_inter.c | 11 +++ src/p_mobj.c | 5 ++ src/p_saveg.c | 12 +++ 15 files changed, 404 insertions(+), 4 deletions(-) create mode 100644 src/objects/amps.c diff --git a/src/d_player.h b/src/d_player.h index 69a4207c9..5513a6043 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -1029,6 +1029,13 @@ struct player_t UINT8 ringboxdelay; // Delay until Ring Box auto-activates UINT8 ringboxaward; // Where did we stop? + UINT8 amps; + UINT8 ampsounds; + UINT8 ampspending; + + UINT16 overdriveboost; + fixed_t overdrivepower; + UINT8 itemflags; // holds IF_ flags (see itemflags_t) fixed_t outrun; // Milky Way road effect diff --git a/src/deh_tables.c b/src/deh_tables.c index df818c094..c40d56be3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -2636,6 +2636,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_WAYPOINTSPLAT", "S_EGOORB", + "S_AMPS", + "S_WATERTRAIL1", "S_WATERTRAIL2", "S_WATERTRAIL3", @@ -3937,6 +3939,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_IPULLUP", "MT_PULLUPHOOK", + + "MT_AMPS", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index c639c7c35..d4366ed19 100644 --- a/src/info.c +++ b/src/info.c @@ -577,6 +577,8 @@ char sprnames[NUMSPRITES + 1][5] = "WAYP", "EGOO", + "AMPA", + "WTRL", // Water Trail "GCHA", // follower: generic chao @@ -3168,6 +3170,8 @@ state_t states[NUMSTATES] = {SPR_WAYP, 1|FF_FLOORSPRITE, 1, {NULL}, 0, 0, S_NULL}, // S_WAYPOINTSPLAT {SPR_EGOO, 0, 1, {NULL}, 0, 0, S_NULL}, // S_EGOORB + {SPR_AMPA, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_AMPS + // Water Trail {SPR_WTRL, FF_PAPERSPRITE , 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL1 {SPR_WTRL, FF_PAPERSPRITE|1, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL2 @@ -22073,6 +22077,32 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOCLIPHEIGHT|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP, // flags S_NULL // raisestate }, + { // MT_AMPS + 3444, // doomednum + S_AMPS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags + S_NULL // raisestate + }, }; diff --git a/src/info.h b/src/info.h index dc9006856..fa8e3fc1b 100644 --- a/src/info.h +++ b/src/info.h @@ -1116,6 +1116,8 @@ typedef enum sprite SPR_WAYP, SPR_EGOO, + SPR_AMPA, + SPR_WTRL, // Water Trail SPR_GCHA, // follower: generic chao @@ -3662,6 +3664,8 @@ typedef enum state S_WAYPOINTSPLAT, S_EGOORB, + S_AMPS, + S_WATERTRAIL1, S_WATERTRAIL2, S_WATERTRAIL3, @@ -4990,6 +4994,8 @@ typedef enum mobj_type MT_IPULLUP, MT_PULLUPHOOK, + MT_AMPS, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_collide.cpp b/src/k_collide.cpp index eb9c788e0..67fcfdfa9 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -29,6 +29,7 @@ #include "m_random.h" #include "k_hud.h" // K_AddMessage #include "m_easing.h" +#include "r_skins.h" angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2) { @@ -694,6 +695,11 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t2, sfx_kdtrg1); } + if (t1->tracer && t1->tracer->player) + { + K_SpawnAmps(t1->tracer->player, 20, t1); + } + if (draggeddroptarget && !P_MobjWasRemoved(draggeddroptarget) && draggeddroptarget->player) { // The following removes t1, be warned diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 6f74c996b..d91ef4368 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -107,6 +107,9 @@ static patch_t *kp_ringdebtminus; static patch_t *kp_ringdebtminussmall; static patch_t *kp_ringspblock[16]; static patch_t *kp_ringspblocksmall[16]; +static patch_t *kp_amps[7][12]; +static patch_t *kp_amps_underlay[12]; +static patch_t *kp_overdrive[32]; static patch_t *kp_speedometersticker; static patch_t *kp_speedometerlabel[4]; @@ -417,6 +420,47 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_ring[i], "%s", buffer); } + // Amps + { + // Levels 1-6 + sprintf(buffer, "b_xAMPxx"); + for (i = 0; i < 6; i++) + { + buffer[2] = '0'+i+1; + for (j = 0; j < 12; j++) + { + buffer[6] = '0'+((j) / 10); + buffer[7] = '0'+((j) % 10); + HU_UpdatePatch(&kp_amps[i][j], "%s", buffer); + } + } + + // Level 7 + buffer[2] = '7'; + buffer[1] = 'A'; + for (j = 0; j < 12; j++) + { + buffer[6] = '0'+((j) / 10); + buffer[7] = '0'+((j) % 10); + HU_UpdatePatch(&kp_amps[i][j], "%s", buffer); + } + buffer[1] = 'B'; + for (j = 0; j < 12; j++) + { + buffer[6] = '0'+((j) / 10); + buffer[7] = '0'+((j) % 10); + HU_UpdatePatch(&kp_amps_underlay[j], "%s", buffer); + } + } + + sprintf(buffer, "b_OVRDxx"); + for (i = 0; i < 32; i++) + { + buffer[6] = '0'+((i) / 10); + buffer[7] = '0'+((i) % 10); + HU_UpdatePatch(&kp_overdrive[i], "%s", buffer); + } + HU_UpdatePatch(&kp_ringdebtminus, "RDEBTMIN"); sprintf(buffer, "SPBRNGxx"); @@ -3125,8 +3169,28 @@ static void K_drawRingCounter(boolean gametypeinfoshown) .align(Draw::Align::kCenter) .width(uselives ? (stplyr->lives >= 10 ? 70 : 64) : 33) .small_sticker(); + + if (stplyr->overdriveboost) + { + V_DrawMappedPatch(LAPS_X+7-8, fy-5-8, V_HUDTRANS|V_SLIDEIN|splitflags, kp_overdrive[leveltime%32], R_GetTranslationColormap(TC_RAINBOW, static_cast(stplyr->skincolor), GTC_CACHE)); + } + else + { + V_DrawMappedPatch(LAPS_X+ringx+7, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_ring[ringanim_realframe], (colorring ? ringmap : NULL)); + + if (stplyr->amps) + { + UINT8 amplevel = std::min(stplyr->amps / AMPLEVEL, 6); + + V_DrawMappedPatch(LAPS_X+7-7, fy-5-8, V_HUDTRANS|V_SLIDEIN|splitflags, kp_amps[amplevel][leveltime%12], R_GetTranslationColormap(TC_RAINBOW, static_cast(stplyr->skincolor), GTC_CACHE)); + if (amplevel == 6) + { + V_DrawMappedPatch(LAPS_X+7-7, fy-5-8, V_ADD|V_HUDTRANS|V_SLIDEIN|splitflags, kp_amps_underlay[leveltime%12], R_GetTranslationColormap(TC_RAINBOW, static_cast(stplyr->skincolor), GTC_CACHE)); + } + } + } + - V_DrawMappedPatch(LAPS_X+ringx+7, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_ring[ringanim_realframe], (colorring ? ringmap : NULL)); // "Why fy-4? Why LAPS_X+29+1?" // "use magic numbers" - jartha 2024-03-05 diff --git a/src/k_kart.c b/src/k_kart.c index 7d6bba2fe..b55d7a8be 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2012,6 +2012,12 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top) fast->color = SKINCOLOR_WHITE; fast->colorized = true; } + else if (player->overdriveboost) + { + fast->color = player->skincolor; + fast->renderflags |= RF_ADD; + fast->scale *= 2; + } else if (player->ringboost) { UINT8 ringboostcolors[] = {SKINCOLOR_AQUAMARINE, SKINCOLOR_EMERALD, SKINCOLOR_GARDEN, SKINCOLOR_CROCODILE, SKINCOLOR_BANANA}; @@ -3512,6 +3518,23 @@ static void K_GetKartBoostPower(player_t *player) ); // + 80% top speed (peak), +400% acceleration (peak), +20% handling } + if (player->overdriveboost) + { + ADDBOOST( + Easing_InCubic( + player->overdrivepower, + 0, + 5*FRACUNIT/10 + ), + Easing_InSine( + player->overdrivepower, + 0, + 3*FRACUNIT + ), + 1*SLIPTIDEHANDLING/5 + ); // + 80% top speed (peak), +400% acceleration (peak), +20% handling + } + if (player->spindashboost) // Spindash boost { const fixed_t MAXCHARGESPEED = K_GetSpindashChargeSpeed(player); @@ -3575,11 +3598,14 @@ static void K_GetKartBoostPower(player_t *player) if (player->ringboost) // Ring Boost { + fixed_t ringboost_base = FRACUNIT/4; + if (player->overdriveboost) + ringboost_base += FRACUNIT/2; // 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.) fixed_t rb = FixedDiv(player->ringboost * FRACUNIT, max(FRACUNIT, K_RingDurationBoost(player))); ADDBOOST( - FRACUNIT/4 + FixedMul(FRACUNIT / 1750, rb), + ringboost_base + FixedMul(FRACUNIT / 1750, rb), 4*FRACUNIT, Easing_InCubic(min(FRACUNIT, rb / (TICRATE*12)), 0, 2*SLIPTIDEHANDLING/5) ); // + 20% + ???% top speed, + 400% acceleration, +???% handling @@ -3969,6 +3995,44 @@ angle_t K_MomentumAngleReal(const mobj_t *mo) } } +void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact) +{ + if (gametyperules & GTR_SPHERES) + return; + + // Give that Sonic guy some help. + UINT16 scaledamps = min(amps, amps * (10 + player->kartspeed - player->kartweight) / 10); + + for (int i = 0; i < (scaledamps/2); i++) + { + mobj_t *pickup = P_SpawnMobj(impact->x, impact->y, impact->z, MT_AMPS); + pickup->momx = P_RandomRange(PR_ITEM_DEBRIS, -40*mapobjectscale, 40*mapobjectscale); + pickup->momy = P_RandomRange(PR_ITEM_DEBRIS, -40*mapobjectscale, 40*mapobjectscale); + pickup->momz = P_RandomRange(PR_ITEM_DEBRIS, -40*mapobjectscale, 40*mapobjectscale); + pickup->color = player->skincolor; + P_SetTarget(&pickup->target, player->mo); + player->ampspending++; + } +} + +void K_AwardPlayerAmps(player_t *player, UINT8 amps) +{ + UINT16 getamped = player->amps + amps; + + if (getamped > 200) + player->amps = 200; + else + player->amps = getamped; + + player->ampsounds++; + player->ampspending--; + + if (player->rings <= 0 && player->ampspending == 0) + { + K_Overdrive(player); + } +} + void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload) { UINT16 superring; @@ -3994,6 +4058,24 @@ void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload) player->superring = superring; } +boolean K_Overdrive(player_t *player) +{ + if (player->amps == 0) + return false; + + K_SpawnDriftBoostExplosion(player, 3); + K_SpawnDriftElectricSparks(player, player->skincolor, true); + S_StartSound(player->mo, sfx_cdfm35); + S_StartSound(player->mo, sfx_cdfm13); + + player->overdriveboost += (player->amps)*6; + player->overdrivepower = FRACUNIT; + + player->amps = 0; + + return true; +} + void K_DoInstashield(player_t *player) { mobj_t *layera; @@ -7246,6 +7328,7 @@ void K_DropHnextList(player_t *player) dropwork->momy = work->momy; dropwork->momz = work->momz; dropwork->reactiontime = work->reactiontime; + dropwork->tracer = work->tracer; P_SetMobjState(dropwork, mobjinfo[type].painstate); } } @@ -8987,6 +9070,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->wavedashboost--; } + if (player->overdriveboost > 0 && onground == true) + { + player->overdriveboost--; + } + if (player->wavedashboost == 0 || player->wavedashpower > FRACUNIT) { player->wavedashpower = FRACUNIT; // Safety @@ -9038,6 +9126,36 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_DoIngameRespawn(player); } + if (player->ampsounds && (leveltime%2)) + { + if (P_IsDisplayPlayer(player)) + { + S_StartSoundAtVolume(NULL, sfx_mbs43, 255); + S_StartSoundAtVolume(NULL, sfx_mbs43, 255); + } + else + { + S_StartSoundAtVolume(NULL, sfx_mbs43, 127); + } + player->ampsounds--; + + if (player->ampsounds == 0) + { + UINT8 amplevel = player->amps / AMPLEVEL; + static sfxenum_t bwips[7] = {sfx_mbs4c, + sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50, + sfx_mbs51, sfx_mbs52}; + amplevel = min(amplevel, 6); + + if (P_IsDisplayPlayer(player)) + { + S_StartSound(NULL, bwips[amplevel]); + S_StartSound(NULL, bwips[amplevel]); + } + } + } + + // Don't tick down while in damage state. // There may be some maps where the timer activates for // a moment during normal play, but would quickly correct @@ -9698,6 +9816,22 @@ void K_KartResetPlayerColor(player_t *player) goto finalise; } + if (player->overdriveboost && (leveltime & 1)) + { + player->mo->colorized = true; + fullbright = true; + player->mo->color = player->skincolor; + goto finalise; + + } + else if (player->overdriveboost) + { + player->mo->colorized = true; + fullbright = true; + player->mo->color = SKINCOLOR_WHITE; + goto finalise; + } + if (player->ringboost && (leveltime & 1)) // ring boosting { player->mo->colorized = true; @@ -11821,6 +11955,9 @@ static void K_KartSpindashWind(mobj_t *parent) if (parent->player && parent->player->wavedashboost) P_SetScale(wind, wind->scale * 2); + if (parent->player && parent->player->overdriveboost) + P_SetScale(wind, wind->scale * 2); + if (parent->momx || parent->momy) wind->angle = R_PointToAngle2(0, 0, parent->momx, parent->momy); else @@ -11888,6 +12025,11 @@ static void K_KartSpindash(player_t *player) K_KartSpindashWind(player->mo); } + if ((player->overdriveboost > 0) && (spawnWind == true)) + { + K_KartSpindashWind(player->mo); + } + if (player->spindashboost > (TICRATE/2)) { K_KartSpindashDust(player->mo); @@ -12735,6 +12877,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->ringdelay = tiereddelay; else player->ringdelay = 3; + + if (player->rings == 0) + K_Overdrive(player); } } @@ -13043,6 +13188,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) mo->movecount = 1; mo->movedir = 1; mo->cusval = player->itemscale; + P_SetTarget(&mo->tracer, player->mo); P_SetTarget(&mo->target, player->mo); P_SetTarget(&player->mo->hnext, mo); } @@ -13051,7 +13197,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) { player->itemamount--; - K_ThrowKartItem(player, (player->throwdir > 0), MT_DROPTARGET, -1, 0, 0); + mobj_t *drop = K_ThrowKartItem(player, (player->throwdir > 0), MT_DROPTARGET, -1, 0, 0); + P_SetTarget(&drop->tracer, player->mo); K_PlayAttackTaunt(player->mo); player->itemflags &= ~IF_ITEMOUT; K_UpdateHnextList(player, true); diff --git a/src/k_kart.h b/src/k_kart.h index 4c67b23df..9dd5ae478 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -50,6 +50,8 @@ Make sure this matches the actual number of states #define MINCOMBOFLOAT (mapobjectscale*1) #define MAXCOMBOTIME (TICRATE*4) +#define AMPLEVEL (30) + #define FLAMESHIELD_MAX (120) #define RR_PROJECTILE_FUSE (8*TICRATE) @@ -129,7 +131,10 @@ void K_KartPlayerAfterThink(player_t *player); angle_t K_MomentumAngleEx(const mobj_t *mo, const fixed_t threshold); angle_t K_MomentumAngleReal(const mobj_t *mo); #define K_MomentumAngle(mo) K_MomentumAngleEx(mo, 6 * mo->scale) +void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact); +void K_AwardPlayerAmps(player_t *player, UINT8 amps); void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload); +boolean K_Overdrive(player_t *player); void K_DoInstashield(player_t *player); void K_DoPowerClash(mobj_t *t1, mobj_t *t2); void K_DoGuardBreak(mobj_t *t1, mobj_t *t2); diff --git a/src/k_objects.h b/src/k_objects.h index 6ab2ccaa3..c336956c2 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -139,6 +139,8 @@ void Obj_BlockRingThink(mobj_t *ring); void Obj_BlockBodyThink(mobj_t *body); void Obj_GuardBreakThink(mobj_t *fx); +void Obj_AmpsThink(mobj_t *amps); + void Obj_ChargeAuraThink(mobj_t *aura); void Obj_ChargeFallThink(mobj_t *charge); void Obj_ChargeReleaseThink(mobj_t *release); @@ -161,7 +163,7 @@ void Obj_RandomItemVisuals(mobj_t *mobj); boolean Obj_RandomItemSpawnIn(mobj_t *mobj); fixed_t Obj_RandomItemScale(fixed_t oldScale); void Obj_RandomItemSpawn(mobj_t *mobj); -#define RINGBOX_TIME (105) +#define RINGBOX_TIME (70) /* Gachabom Rebound */ void Obj_GachaBomReboundThink(mobj_t *mobj); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 8bd5821db..a0129a42f 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -280,6 +280,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->ringboxdelay); else if (fastcmp(field,"ringboxaward")) lua_pushinteger(L, plr->ringboxaward); + else if (fastcmp(field,"amps")) + lua_pushinteger(L, plr->amps); + else if (fastcmp(field,"ampsounds")) + lua_pushinteger(L, plr->ampsounds); + else if (fastcmp(field,"ampspending")) + lua_pushinteger(L, plr->ampspending); else if (fastcmp(field,"itemflags")) lua_pushinteger(L, plr->itemflags); else if (fastcmp(field,"drift")) @@ -358,8 +364,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->wavedashdelay); else if (fastcmp(field,"wavedashboost")) lua_pushinteger(L, plr->wavedashboost); + else if (fastcmp(field,"overdriveboost")) + lua_pushinteger(L, plr->overdriveboost); else if (fastcmp(field,"wavedashpower")) lua_pushinteger(L, plr->wavedashpower); + else if (fastcmp(field,"overdrivepower")) + lua_pushinteger(L, plr->overdrivepower); else if (fastcmp(field,"speedpunt")) lua_pushinteger(L, plr->speedpunt); else if (fastcmp(field,"trickcharge")) @@ -842,6 +852,12 @@ static int player_set(lua_State *L) plr->ringboxdelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"ringboxaward")) plr->ringboxaward = luaL_checkinteger(L, 3); + else if (fastcmp(field,"amps")) + plr->amps = luaL_checkinteger(L, 3); + else if (fastcmp(field,"ampsounds")) + plr->ampsounds = luaL_checkinteger(L, 3); + else if (fastcmp(field,"ampspending")) + plr->ampspending = luaL_checkinteger(L, 3); else if (fastcmp(field,"itemflags")) plr->itemflags = luaL_checkinteger(L, 3); else if (fastcmp(field,"drift")) @@ -918,8 +934,12 @@ static int player_set(lua_State *L) plr->wavedashdelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"wavedashboost")) plr->wavedashboost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"overdriveboost")) + plr->overdriveboost = luaL_checkinteger(L, 3); else if (fastcmp(field,"wavedashpower")) plr->wavedashpower = luaL_checkinteger(L, 3); + else if (fastcmp(field,"overdrivepower")) + plr->overdrivepower = luaL_checkinteger(L, 3); else if (fastcmp(field,"speedpunt")) plr->speedpunt = luaL_checkinteger(L, 3); else if (fastcmp(field,"trickcharge")) diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index ddc96ef41..487ce232f 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -58,6 +58,7 @@ target_sources(SRB2SDL2 PRIVATE adventure-air-booster.c destroyed-kart.cpp pulley.cpp + amps.c ) add_subdirectory(versus) diff --git a/src/objects/amps.c b/src/objects/amps.c new file mode 100644 index 000000000..eca0a2a29 --- /dev/null +++ b/src/objects/amps.c @@ -0,0 +1,80 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by AJ "Tyron" Martinez. +// Copyright (C) 2024 by Kart Krew +// +// 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 amps.c +/// \brief Amps VFX code. + +#include "../doomdef.h" +#include "../info.h" +#include "../k_objects.h" +#include "../p_local.h" +#include "../k_kart.h" +#include "../k_powerup.h" +#include "../m_random.h" +#include "../r_main.h" +#include "../m_easing.h" + +#define AMP_ARCTIME (8) + +void Obj_AmpsThink (mobj_t *amps) +{ + if (P_MobjWasRemoved(amps->target) + || amps->target->health == 0 + || amps->target->destscale <= 1 // sealed star fall out + || !amps->target->player) + { + P_RemoveMobj(amps); + } + else + { + mobj_t *mo = amps->target; + player_t *player = mo->player; + + fixed_t dist, fakez; + angle_t hang, vang; + + UINT8 damper = 3; + + dist = P_AproxDistance(P_AproxDistance(amps->x - mo->x, amps->y - mo->y), amps->z - mo->z); + + fixed_t vert = dist/3; + fixed_t speed = 45*amps->scale; + + if (amps->extravalue2) + { + if (amps->extravalue1) + amps->extravalue1--; + + fakez = mo->z + (vert * amps->extravalue1 / AMP_ARCTIME); + damper = 1; + } + else + { + amps->extravalue1++; + if (amps->extravalue1 >= AMP_ARCTIME) + amps->extravalue2 = 1; + + fakez = mo->z + vert; + } + + hang = R_PointToAngle2(amps->x, amps->y, mo->x, mo->y); + vang = R_PointToAngle2(amps->z, 0, fakez, dist); + + amps->momx -= amps->momx>>(damper), amps->momy -= amps->momy>>(damper), amps->momz -= amps->momz>>(damper); + amps->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), speed)); + amps->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), speed)); + amps->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), speed); + + if (dist < (120 * amps->scale) && amps->extravalue2) + { + K_AwardPlayerAmps(player, 2); + P_RemoveMobj(amps); + } + } +} \ No newline at end of file diff --git a/src/p_inter.c b/src/p_inter.c index 884091c2d..ac7f41929 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3006,6 +3006,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da sfx = sfx_s3k3a; clash = true; } + else if (player->overdriveboost) + { + clash = true; + } else if (player->hyudorotimer > 0) ; else @@ -3069,6 +3073,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { K_DoPowerClash(target, inflictor); + if (inflictor->type != MT_PLAYER) + { + K_SpawnAmps(player, 5, inflictor); + } + if (inflictor->type == MT_SUPER_FLICKY) { Obj_BlockSuperFlicky(inflictor); @@ -3158,6 +3167,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (source && source != player->mo && source->player) { + K_SpawnAmps(source->player, 20, target); + // Extend the invincibility if the hit was a direct hit. if (inflictor == source && source->player->invincibilitytimer && !K_PowerUpRemaining(source->player, POWERUP_SMONITOR)) diff --git a/src/p_mobj.c b/src/p_mobj.c index e6effb1fc..13fb1b0f5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8580,6 +8580,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; } + case MT_AMPS: + { + Obj_AmpsThink(mobj); + break; + } case MT_BLOCKRING: { Obj_BlockRingThink(mobj); diff --git a/src/p_saveg.c b/src/p_saveg.c index 268fc953b..b7df7f1ea 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -581,7 +581,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT16(save->p, players[i].wavedash); WRITEUINT8(save->p, players[i].wavedashdelay); WRITEUINT16(save->p, players[i].wavedashboost); + WRITEUINT16(save->p, players[i].overdriveboost); WRITEFIXED(save->p, players[i].wavedashpower); + WRITEFIXED(save->p, players[i].overdrivepower); WRITEUINT16(save->p, players[i].speedpunt); WRITEUINT16(save->p, players[i].trickcharge); @@ -627,6 +629,10 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].ringboxdelay); WRITEUINT8(save->p, players[i].ringboxaward); + WRITEUINT8(save->p, players[i].amps); + WRITEUINT8(save->p, players[i].ampsounds); + WRITEUINT8(save->p, players[i].ampspending); + WRITEUINT8(save->p, players[i].itemflags); WRITEFIXED(save->p, players[i].outrun); @@ -1185,7 +1191,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].wavedash = READUINT16(save->p); players[i].wavedashdelay = READUINT8(save->p); players[i].wavedashboost = READUINT16(save->p); + players[i].overdriveboost = READUINT16(save->p); players[i].wavedashpower = READFIXED(save->p); + players[i].overdrivepower = READFIXED(save->p); players[i].speedpunt = READUINT16(save->p); players[i].trickcharge = READUINT16(save->p); @@ -1231,6 +1239,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].ringboxdelay = READUINT8(save->p); players[i].ringboxaward = READUINT8(save->p); + players[i].amps =READUINT8(save->p); + players[i].ampsounds =READUINT8(save->p); + players[i].ampspending =READUINT8(save->p); + players[i].itemflags = READUINT8(save->p); players[i].outrun = READFIXED(save->p);