diff --git a/src/d_main.cpp b/src/d_main.cpp index 9d1b25edb..3eafa8c67 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -272,9 +272,19 @@ void D_ProcessEvents(boolean callresponders) boolean eaten; G_ResetAllDeviceResponding(); - for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + + // Save these in local variables because eventtail != + // eventhead was evaluating true when they were equal, + // but only when using the Y button to restart a Time + // Attack?? + INT32 tail = eventtail; + INT32 head = eventhead; + + eventtail = eventhead; + + for (; tail != head; tail = (tail+1) & (MAXEVENTS-1)) { - ev = &events[eventtail]; + ev = &events[tail]; HandleGamepadDeviceEvents(ev); diff --git a/src/deh_tables.c b/src/deh_tables.c index 5bd5700f9..513a50c46 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3455,6 +3455,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_RANDOMITEM", "MT_SPHEREBOX", "MT_FLOATINGITEM", + "MT_GOTPOWERUP", "MT_ITEMCAPSULE", "MT_ITEMCAPSULE_PART", "MT_MONITOR", diff --git a/src/doomstat.h b/src/doomstat.h index c74dda7ac..ce0782cd9 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -811,6 +811,12 @@ extern struct darkness_t fixed_t value[MAXSPLITSCREENPLAYERS]; } g_darkness; +extern struct musicfade_t +{ + tic_t start, end, fade; + boolean ticked; +} g_musicfade; + #define DEFAULT_GRAVITY (4*FRACUNIT/5) extern fixed_t gravity; extern fixed_t mapobjectscale; diff --git a/src/g_game.c b/src/g_game.c index 4a4d25f1a..5d181a536 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -279,6 +279,7 @@ tic_t racecountdown, exitcountdown, musiccountdown; // for racing exitcondition_t g_exit; darkness_t g_darkness; +musicfade_t g_musicfade; fixed_t gravity; fixed_t mapobjectscale; diff --git a/src/hud/powerup.cpp b/src/hud/powerup.cpp index 5861791be..449236099 100644 --- a/src/hud/powerup.cpp +++ b/src/hud/powerup.cpp @@ -1,3 +1,12 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023-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. +//----------------------------------------------------------------------------- + #include #include @@ -81,7 +90,7 @@ void K_drawKartPowerUps(void) { auto make_drawer = [](int x, int y, Draw::Font font) -> Draw { - return Draw(x, y).font(font).align(Draw::Align::kRight); + return Draw(x, y).font(font).align(Draw::Align::kRight).flags(V_SLIDEIN); }; const int viewnum = R_GetViewNumber(); diff --git a/src/info.c b/src/info.c index 6aa10a510..aa9d66bbc 100644 --- a/src/info.c +++ b/src/info.c @@ -13188,6 +13188,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GOTPOWERUP + -1, // doomednum + S_ITEMICON, // spawnstate + 1, // 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_itpick, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOSQUISH|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_ITEMCAPSULE 2010, // doomednum S_ITEMCAPSULE, // spawnstate @@ -21532,7 +21559,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOGRAVITY|MF_NOCLIP, // flags + MF_SCENERY|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, { // MT_SSCHAINSOUND diff --git a/src/info.h b/src/info.h index 3b26cfefc..442581ac8 100644 --- a/src/info.h +++ b/src/info.h @@ -4475,6 +4475,7 @@ typedef enum mobj_type MT_RANDOMITEM, MT_SPHEREBOX, MT_FLOATINGITEM, + MT_GOTPOWERUP, MT_ITEMCAPSULE, MT_ITEMCAPSULE_PART, MT_MONITOR, diff --git a/src/k_battle.c b/src/k_battle.c index d08fcee2c..5d284bb77 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -175,7 +175,8 @@ void K_CheckBumpers(void) { // If every other player is eliminated, the // last player standing wins by default. - K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL); + if (numingame > 1) + K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL); return; } @@ -653,12 +654,12 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale) if (player->mo->eflags & MFE_VERTICALFLIP) { zpos = cam->z + player->mo->height; - zpos = min(zpos + heightPadding, cam->ceilingz); + zpos = min(zpos + heightPadding, cam->centerceilingz); } else { zpos = cam->z; - zpos = max(zpos - heightPadding, cam->floorz); + zpos = max(zpos - heightPadding, cam->centerfloorz); } flip = P_MobjFlip(player->mo); diff --git a/src/k_battle.h b/src/k_battle.h index f1310e4d1..7806894e5 100644 --- a/src/k_battle.h +++ b/src/k_battle.h @@ -11,6 +11,7 @@ extern "C" { #define BATTLE_SPAWN_INTERVAL (4*TICRATE) #define BATTLE_DESPAWN_TIME (15*TICRATE) #define BATTLE_POWERUP_TIME (30*TICRATE) +#define BATTLE_POWERUP_DROPPED_TIME (15*TICRATE) #define BATTLE_UFO_TIME (20*TICRATE) extern struct battleovertime diff --git a/src/k_kart.c b/src/k_kart.c index 7d933f3ae..6ee8569aa 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -118,6 +118,7 @@ void K_TimerReset(void) { starttime = introtime = 0; memset(&g_darkness, 0, sizeof g_darkness); + memset(&g_musicfade, 0, sizeof g_musicfade); numbulbs = 1; inDuel = rainbowstartavailable = false; linecrossed = 0; @@ -1015,7 +1016,8 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) K_SpawnBumpForObjs(mobj1, mobj2); - if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER) + if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER + && !mobj1->player->powerupVFXTimer && !mobj2->player->powerupVFXTimer) { boolean guard1 = K_PlayerGuard(mobj1->player); boolean guard2 = K_PlayerGuard(mobj2->player); @@ -2212,6 +2214,7 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) if (!podiumspecial) { distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, victim->x, victim->y); + distance = R_PointToDist2(0, glancePlayer->mo->z, distance, victim->z); if (distance > maxdistance) { @@ -4828,7 +4831,7 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) player->ringvisualwarning = TICRATE*2; player->stingfx = true; - if (P_IsDisplayPlayer(player)) + if (P_IsDisplayPlayer(player) && !player->exiting) S_StartSoundAtVolume(NULL, sfx_sting0, 200); P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); @@ -8443,6 +8446,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK); + debtflag->old_x = player->mo->old_x; + debtflag->old_y = player->mo->old_y; + debtflag->old_z = player->mo->old_z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale); + P_SetMobjState(debtflag, S_RINGDEBT); P_SetScale(debtflag, (debtflag->destscale = player->mo->scale)); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index c1d8340c4..c64e9cf25 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -918,7 +918,7 @@ void M_DrawMenuMessage(void) } V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2, y, 0, string); - y += 9; + y += 8; } } diff --git a/src/k_objects.h b/src/k_objects.h index 93e6692d0..ee1a24290 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -398,6 +398,10 @@ void Obj_TalkPointInit(mobj_t* mo); void Obj_TalkPointThink(mobj_t* mo); void Obj_TalkPointOrbThink(mobj_t* mo); +/* Power-up Spinner */ +void Obj_SpawnPowerUpSpinner(mobj_t *source, INT32 powerup, tic_t duration); +void Obj_TickPowerUpSpinner(mobj_t *mobj); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 8bc504cbc..5472eec34 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -2,6 +2,7 @@ #include +#include "k_battle.h" #include "k_kart.h" #include "k_objects.h" #include "k_powerup.h" @@ -54,44 +55,45 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) Obj_SpawnPowerUpAura(player); } - S_StartSound(NULL, sfx_gsha7); + S_StartSound(NULL, sfx_gsha7l); player->flashing = 2*TICRATE; - K_AddHitLag(player->mo, BATTLE_POWERUP_VFX_TIME, false); + player->mo->hitlag += BATTLE_POWERUP_VFX_TIME; player->powerupVFXTimer = BATTLE_POWERUP_VFX_TIME; + Obj_SpawnPowerUpSpinner(player->mo, powerup, BATTLE_POWERUP_VFX_TIME); g_darkness.start = leveltime; g_darkness.end = leveltime + BATTLE_POWERUP_VFX_TIME + DARKNESS_FADE_TIME; + g_musicfade.start = leveltime; + g_musicfade.end = g_musicfade.start + 90; + g_musicfade.fade = 20; + g_musicfade.ticked = false; + switch (powerup) { case POWERUP_SMONITOR: - S_StartSound(NULL, sfx_bpwrua); K_AddMessageForPlayer(player, "Got S MONITOR!", true, false); K_DoInvincibility(player, player->invincibilitytimer + time); player->powerup.superTimer += time; break; case POWERUP_BARRIER: - S_StartSound(NULL, sfx_bpwrub); K_AddMessageForPlayer(player, "Got MEGA BARRIER!", true, false); player->powerup.barrierTimer += time; Obj_SpawnMegaBarrier(player); break; case POWERUP_BUMPER: - S_StartSound(NULL, sfx_bpwruc); K_AddMessageForPlayer(player, "Got BUMPER RESTOCK!", true, false); K_GiveBumpersToPlayer(player, nullptr, 5); break; case POWERUP_BADGE: - S_StartSound(NULL, sfx_bpwrud); K_AddMessageForPlayer(player, "Got RHYTHM BADGE!", true, false); player->powerup.rhythmBadgeTimer += time; break; case POWERUP_SUPERFLICKY: - S_StartSound(NULL, sfx_bpwrue); K_AddMessageForPlayer(player, "Got SUPER FLICKY!", true, false); if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { @@ -104,7 +106,6 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) break; case POWERUP_POINTS: - S_StartSound(NULL, sfx_bpwruf); K_AddMessageForPlayer(player, "Got 6 POINTS!", true, false); K_GivePointsToPlayer(player, nullptr, 6); @@ -127,7 +128,7 @@ void K_DropPowerUps(player_t* player) if (remaining) { - K_DropPaperItem(player, powerup, remaining); + K_DropPaperItem(player, powerup, std::max(remaining, BATTLE_POWERUP_DROPPED_TIME)); callback(); } }; diff --git a/src/k_respawn.c b/src/k_respawn.c index 3cd82d1d0..8196c438b 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -556,7 +556,7 @@ static void K_MovePlayerToRespawnPoint(player_t *player) if (player->respawn.init == false && player->respawn.fromRingShooter == false - && K_PlayerEBrake(player) == true) + && K_PressingEBrake(player) == true) { // Manual drop! player->respawn.state = RESPAWNST_DROP; diff --git a/src/music.cpp b/src/music.cpp index 953f20071..7205c2535 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -71,6 +71,7 @@ void Music_Init(void) tune.song = "kgrow"; tune.priority = 20; tune.resume_fade_in = 200; + tune.use_level_volume = true; } { @@ -78,6 +79,7 @@ void Music_Init(void) tune.song = "kinvnc"; tune.priority = 21; + tune.use_level_volume = true; } { diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index fce16395a..0dde3da9f 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources(SRB2SDL2 PRIVATE waterfall-particle.c sealed-star.c talk-point.cpp + powerup-spinner.cpp ) add_subdirectory(versus) diff --git a/src/objects/audience.c b/src/objects/audience.c index b5814ae16..9558dfe9f 100644 --- a/src/objects/audience.c +++ b/src/objects/audience.c @@ -123,11 +123,11 @@ Obj_AudienceInit // The following is derived from the default bobamp if (mobj->type != MT_EMBLEM && !(mobj->flags & MF_NOGRAVITY) && followers[followerpick].bobamp < 4*FRACUNIT) { - audience_bobamp(mobj) = 4*mobj->scale; + audience_bobamp(mobj) = 4*mapobjectscale; } else { - audience_bobamp(mobj) = FixedMul(mobj->scale, followers[followerpick].bobamp); + audience_bobamp(mobj) = FixedMul(mapobjectscale, followers[followerpick].bobamp); } } diff --git a/src/objects/broly.hpp b/src/objects/broly.hpp index d75a7fc4b..64f7f58da 100644 --- a/src/objects/broly.hpp +++ b/src/objects/broly.hpp @@ -44,7 +44,7 @@ struct Broly : Mobj bool valid() const { return duration(); } - tic_t remaining() const { return tics - kBufferTics; } + tic_t remaining() const { return tics > kBufferTics ? tics - kBufferTics : 0u; } Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } diff --git a/src/objects/powerup-spinner.cpp b/src/objects/powerup-spinner.cpp new file mode 100644 index 000000000..248a95b69 --- /dev/null +++ b/src/objects/powerup-spinner.cpp @@ -0,0 +1,97 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include + +#include "objects.hpp" + +#include "../m_easing.h" +#include "../m_fixed.h" +#include "../tables.h" + +using namespace srb2::objects; + +namespace +{ + +struct Spinner : Mobj +{ + static constexpr int kDuration = 40; + + void extravalue1() = delete; + INT32 powerup() const { return mobj_t::extravalue1; } + void powerup(INT32 n) { mobj_t::extravalue1 = n; } + + void extravalue2() = delete; + INT32 duration() const { return mobj_t::extravalue2; } + void duration(INT32 n) { mobj_t::extravalue2 = n; } + + static void spawn(Mobj* source, INT32 powerup, tic_t duration) + { + Spinner* x = Mobj::spawn(source->pos(), MT_GOTPOWERUP); + K_UpdateMobjItemOverlay(x, powerup, 1); + x->frame |= FF_PAPERSPRITE | FF_ADD; + x->fuse = duration; + x->powerup(powerup); + x->duration(duration); + } + + void think() + { + fixed_t f = FRACUNIT - std::clamp(fuse, 0, duration()) * FRACUNIT / std::max(duration(), 1); + + if (fuse == duration() - 20) + { + S_StartSound(nullptr, sound()); + } + + angle += Easing_InQuad(f, ANGLE_11hh, ANGLE_45); + renderflags = (renderflags & ~RF_TRANSMASK) | (Easing_Linear(f, 0, 9) << RF_TRANSSHIFT); + spritescale({Easing_Linear(f, 4*FRACUNIT, FRACUNIT/4), Easing_Linear(f, FRACUNIT, 6*FRACUNIT)}); + + if (--fuse <= 0) + { + remove(); + } + } + +private: + sfxenum_t sound() const + { + switch (powerup()) + { + case POWERUP_SMONITOR: + return sfx_bpwrua; + case POWERUP_BARRIER: + return sfx_bpwrub; + case POWERUP_BUMPER: + return sfx_bpwruc; + case POWERUP_BADGE: + return sfx_bpwrud; + case POWERUP_SUPERFLICKY: + return sfx_bpwrue; + case POWERUP_POINTS: + return sfx_bpwruf; + default: + return sfx_thok; + } + } +}; + +}; // namespace + +void Obj_SpawnPowerUpSpinner(mobj_t *source, INT32 powerup, tic_t duration) +{ + Spinner::spawn(static_cast(source), powerup, duration); +} + +void Obj_TickPowerUpSpinner(mobj_t *mobj) +{ + static_cast(mobj)->think(); +} diff --git a/src/objects/shrink.c b/src/objects/shrink.c index 58b6cf856..1aa3fc3d0 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -341,6 +341,7 @@ static void ShrinkLaserThinker(mobj_t *pohbee, mobj_t *gun, mobj_t *laser) particle->color = laser->color; P_SetScale(particle, particle->scale * 2); + particle->cusval = particle->scale; // Store for later. particle->destscale = 0; //particle->momz = 2 * particle->scale * P_MobjFlip(particle); @@ -535,6 +536,14 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) owner = pohbee_owner(pohbee); prevTimer = victim->player->growshrinktimer; + fixed_t scale = FRACUNIT; // Used if you hit the gun/laser. + + if (gun->type == MT_SHRINK_PARTICLE && gun->cusval != 0) // Hit the laser trail, scale the punishment down. + { + fixed_t normalizer = FixedDiv(FRACUNIT, gun->cusval); // cusval = original scale of the particle, as it eases down to 0 + scale = FixedMul(gun->scale, normalizer); + } + if (owner != NULL && victim == owner) { // Belongs to us. Give us Grow! @@ -576,17 +585,21 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) } else { + // Bullshit contact. Let 'em off for free. + if (scale < FRACUNIT/4) + return true; + if (prevTimer > 0) { // Dock some Grow time. // (Hack-adjacent: Always make sure there's a tic left so standard timer handling can remove the effect properly.) - victim->player->growshrinktimer -= min(3*TICRATE/2, victim->player->growshrinktimer - 1); + victim->player->growshrinktimer -= min(FixedInt(FixedMul(FRACUNIT*3*TICRATE/2, scale)), victim->player->growshrinktimer - 1); S_StartSound(victim, sfx_s3k40); } else { // Start shrinking! - victim->player->growshrinktimer -= 5*TICRATE; + victim->player->growshrinktimer -= FixedInt(FixedMul(FRACUNIT*5*TICRATE, scale)); S_StartSound(victim, sfx_kc59); // I don't think you ever get to hear this while the pohbee laser is in your teeth, but best effort. if (prevTimer >= 0) diff --git a/src/objects/spb.c b/src/objects/spb.c index 89ac8f174..2c0d51fa9 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -679,7 +679,7 @@ static void SPBChase(mobj_t *spb, mobj_t *bestMobj) return; } - if (chase->hitlag) + if (chase->hitlag > 0) { // If the player is frozen, the SPB should be too. spb->hitlag = max(spb->hitlag, chase->hitlag); diff --git a/src/p_inter.c b/src/p_inter.c index 048034486..aa77ea26c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1362,8 +1362,6 @@ void P_CheckTimeLimit(void) thinker_t *th; mobj_t *center = NULL; - fixed_t rx, ry; - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { mobj_t *thismo; @@ -1397,18 +1395,17 @@ void P_CheckTimeLimit(void) // Get largest radius from center point to minimap edges - rx = max( - abs(battleovertime.x - (minimapinfo.min_x * FRACUNIT)), - abs(battleovertime.x - (minimapinfo.max_x * FRACUNIT)) - ); - - ry = max( - abs(battleovertime.y - (minimapinfo.min_y * FRACUNIT)), - abs(battleovertime.y - (minimapinfo.max_y * FRACUNIT)) - ); + fixed_t r = 0; + fixed_t n; +#define corner(px, py) ((n = FixedHypot(battleovertime.x - (px), battleovertime.y - (py))), r = max(r, n)) + corner(minimapinfo.min_x * FRACUNIT, minimapinfo.min_y * FRACUNIT); + corner(minimapinfo.min_x * FRACUNIT, minimapinfo.max_y * FRACUNIT); + corner(minimapinfo.max_x * FRACUNIT, minimapinfo.min_y * FRACUNIT); + corner(minimapinfo.max_x * FRACUNIT, minimapinfo.max_y * FRACUNIT); +#undef corner battleovertime.initial_radius = min( - max(max(rx, ry), 4096 * mapobjectscale), + max(r, 4096 * mapobjectscale), // Prevent overflow in K_RunBattleOvertime FixedDiv(INT32_MAX, M_PI_FIXED) / 2 ); diff --git a/src/p_local.h b/src/p_local.h index f36337615..c9e1860c1 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -112,6 +112,10 @@ struct camera_t fixed_t floorz; fixed_t ceilingz; + // From the player + fixed_t centerfloorz; + fixed_t centerceilingz; + // For movement checking. fixed_t radius; fixed_t height; diff --git a/src/p_mobj.c b/src/p_mobj.c index 497275b93..488193e3a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6596,6 +6596,11 @@ static void P_MobjSceneryThink(mobj_t *mobj) Obj_SSGobletMobjThink(mobj); return; } + case MT_GOTPOWERUP: + { + Obj_TickPowerUpSpinner(mobj); + return; + } default: if (mobj->fuse) { // Scenery object fuse! Very basic! diff --git a/src/p_saveg.c b/src/p_saveg.c index b89ee4412..8a1956ba4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6567,6 +6567,11 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT32(save->p, g_darkness.start); WRITEUINT32(save->p, g_darkness.end); + WRITEUINT32(save->p, g_musicfade.start); + WRITEUINT32(save->p, g_musicfade.end); + WRITEUINT32(save->p, g_musicfade.fade); + WRITEUINT8(save->p, g_musicfade.ticked); + WRITEUINT16(save->p, numchallengedestructibles); // Is it paused? @@ -6753,6 +6758,11 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) g_darkness.start = READUINT32(save->p); g_darkness.end = READUINT32(save->p); + g_musicfade.start = READUINT32(save->p); + g_musicfade.end = READUINT32(save->p); + g_musicfade.fade = READUINT32(save->p); + g_musicfade.ticked = READUINT8(save->p); + numchallengedestructibles = READUINT16(save->p); // Is it paused? diff --git a/src/p_tick.c b/src/p_tick.c index 9f0b33da7..bc78f291a 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -808,6 +808,22 @@ static void P_TickDarkness(void) } } +static void P_TickMusicFade(void) +{ + if (leveltime >= g_musicfade.start && leveltime <= g_musicfade.end) + { + INT32 half = (g_musicfade.end - g_musicfade.start) / 2; + INT32 fade = max(1, g_musicfade.fade); + INT32 mid = half - fade; + INT32 t = abs((INT32)leveltime - (INT32)(g_musicfade.start + half)); + Music_LevelVolume((max(t, mid) - mid) * 100 / fade); + } + else if (!g_musicfade.ticked) + Music_LevelVolume(100); + + g_musicfade.ticked = true; +} + // // P_Ticker // @@ -1102,6 +1118,7 @@ void P_Ticker(boolean run) racecountdown--; P_TickDarkness(); + P_TickMusicFade(); if (exitcountdown >= 1) { diff --git a/src/p_user.c b/src/p_user.c index 1fdafd4aa..2712a126a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -712,7 +712,7 @@ void P_EndingMusic(void) jingle = "_win"; } - if (modeattacking) + if (modeattacking && !K_IsPlayerLosing(bestPlayer)) { if (players[consoleplayer].realtime < oldbest && oldbest != (tic_t)UINT32_MAX) jingle = "newrec"; @@ -3053,6 +3053,8 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->x = x; thiscam->y = y; thiscam->z = z; + thiscam->centerfloorz = player->mo->floorz; + thiscam->centerceilingz = player->mo->ceilingz; thiscam->angle = player->mo->angle; thiscam->aiming = 0; @@ -3570,6 +3572,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall R_ResetViewInterpolation(num + 1); } + thiscam->centerfloorz = mo->floorz; + thiscam->centerceilingz = mo->ceilingz; + return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); } diff --git a/src/sounds.c b/src/sounds.c index ffe57da83..d1e4a7f65 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1420,6 +1420,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"gsha5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gsha7l",false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gshaa", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 4a7c0bfc7..86f012c11 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1496,6 +1496,7 @@ typedef enum sfx_gsha5, sfx_gsha6, sfx_gsha7, + sfx_gsha7l, sfx_gsha8, sfx_gsha9, sfx_gshaa, diff --git a/src/typedef.h b/src/typedef.h index e866a22a9..ac9bbff5f 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -143,6 +143,7 @@ TYPEDEF (cupheader_t); TYPEDEF (unloaded_cupheader_t); TYPEDEF (exitcondition_t); TYPEDEF (darkness_t); +TYPEDEF (musicfade_t); // font.h TYPEDEF (font_t);