From ebb79fa34bc8728b603599d7e2865d9f45b723f2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 18:09:03 -0700 Subject: [PATCH 01/47] Add player_t.cameraOffset, offset chasecam Z position --- src/d_player.h | 1 + src/k_kart.c | 2 ++ src/p_user.c | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 35795e9fa..6d6e887d1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -504,6 +504,7 @@ struct player_t fixed_t deltaviewheight; // bounded/scaled total momentum. fixed_t bob; + fixed_t cameraOffset; skybox_t skybox; diff --git a/src/k_kart.c b/src/k_kart.c index 7e49c0847..815004164 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7794,6 +7794,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->spritexoffset = 0; player->mo->spriteyoffset = 0; + player->cameraOffset = 0; + if (player->curshield == KSHIELD_TOP) { mobj_t *top = K_GetGardenTop(player); diff --git a/src/p_user.c b/src/p_user.c index d2f148283..63b6ca6a9 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3542,6 +3542,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall z = mo->z + pviewheight + distz; } + z += player->cameraOffset; + // point viewed by the camera // this point is just 64 unit forward the player dist = 64*cameraScale; @@ -3586,13 +3588,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (mo->eflags & MFE_VERTICALFLIP) { - angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, mo->z + mo->height - player->mo->height); + angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, mo->z + mo->height - player->mo->height + player->cameraOffset); if (thiscam->pitch < ANGLE_180 && thiscam->pitch > angle) angle += (thiscam->pitch - angle)/2; } else { - angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + player->mo->height); + angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + player->mo->height + player->cameraOffset); if (thiscam->pitch >= ANGLE_180 && thiscam->pitch < angle) angle -= (angle - thiscam->pitch)/2; } From a680e1167559df9c5cad65ff6628d27da54707a4 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 18:10:56 -0700 Subject: [PATCH 02/47] Instawhip: adjust player sprzoff and cameraOffset instead of momz Since gravity is not involved, this will be more consistent but it is also slightly different than before. I tried to match it closely to how it behaved before, though. --- src/k_kart.c | 20 +++++++++++++++++--- src/k_kart.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 815004164..6b06c1d8a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7816,6 +7816,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } + if (!P_MobjWasRemoved(player->whip)) + { + // Linear acceleration and deceleration to a peak. + // There is a constant total time to complete but the + // acceleration and deceleration times can be made + // asymmetrical. + const fixed_t hop = 16 * mapobjectscale; + const INT32 duration = 12; + const INT32 mid = (duration / 2) - 2; + const INT32 t = (duration - mid) - player->whip->fuse; + + player->cameraOffset = hop - (abs(t * hop) / (t < 0 ? mid : duration - mid)); + player->mo->sprzoff += player->cameraOffset; + } + K_UpdateOffroad(player); K_UpdateDraft(player); K_UpdateEngineSounds(player); // Thanks, VAda! @@ -10945,9 +10960,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&whip->target, player->mo); K_MatchGenericExtraFlags(whip, player->mo); P_SpawnFakeShadow(whip, 20); - whip->fuse = 12; // Changing instawhip animation duration? Look here - player->flashing = max(player->flashing, 12); - player->mo->momz += 4*mapobjectscale; + whip->fuse = INSTAWHIP_DURATION; + player->flashing = max(player->flashing, INSTAWHIP_DURATION); if (!K_PowerUpRemaining(player, POWERUP_BADGE)) { diff --git a/src/k_kart.h b/src/k_kart.h index 22e7ac9fa..8982e9d75 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -29,6 +29,7 @@ Make sure this matches the actual number of states #define GROW_PHYSICS_SCALE (3*FRACUNIT/2) #define SHRINK_PHYSICS_SCALE (3*FRACUNIT/4) +#define INSTAWHIP_DURATION (12) #define INSTAWHIP_COOLDOWN (TICRATE*2) #define INSTAWHIP_STARTOFRACE (255) #define INSTAWHIP_STARTOFBATTLE (1) From fe6da4e0875b7c1a2c62d03c770be5fc806f1bc8 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 18:12:59 -0700 Subject: [PATCH 03/47] Instawhip: consistently flicker on opposite frame of player flashing tics --- src/objects/instawhip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objects/instawhip.c b/src/objects/instawhip.c index 64ddd8ae5..dc1e410ed 100644 --- a/src/objects/instawhip.c +++ b/src/objects/instawhip.c @@ -34,7 +34,8 @@ void Obj_InstaWhipThink (mobj_t *whip) // Visuals whip->renderflags |= RF_NOSPLATBILLBOARD|RF_FULLBRIGHT; - if (whip->renderflags & RF_DONTDRAW) + // This is opposite of player flashing tics + if (leveltime & 1) whip->renderflags &= ~RF_DONTDRAW; else whip->renderflags |= RF_DONTDRAW; From 4bdc05824c7bd342c08be52690d058b2604ae895 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 03:24:22 -0700 Subject: [PATCH 04/47] Add Obj_BeginEmeraldOrbit, seamless transition into orbit --- src/k_objects.h | 1 + src/objects/emerald.c | 94 ++++++++++++++++++++++++++++++++++--------- src/objects/ufo.c | 2 +- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/k_objects.h b/src/k_objects.h index 8066e7078..513f88fdb 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -207,6 +207,7 @@ void Obj_SneakerPanelCollide(mobj_t *pad, mobj_t *mo); /* Emerald */ void Obj_SpawnEmeraldSparks(mobj_t *source); void Obj_EmeraldThink(mobj_t *emerald); +void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time); #ifdef __cplusplus } // extern "C" diff --git a/src/objects/emerald.c b/src/objects/emerald.c index 40524cd12..6ef557b12 100644 --- a/src/objects/emerald.c +++ b/src/objects/emerald.c @@ -3,8 +3,16 @@ #include "../info.h" #include "../m_random.h" #include "../p_local.h" +#include "../r_main.h" #include "../tables.h" +#define emerald_type(o) ((o)->extravalue1) +#define emerald_anim_start(o) ((o)->movedir) +#define emerald_revolution_time(o) ((o)->threshold) +#define emerald_start_radius(o) ((o)->movecount) +#define emerald_target_radius(o) ((o)->extravalue2) +#define emerald_z_shift(o) ((o)->reactiontime) + void Obj_SpawnEmeraldSparks(mobj_t *mobj) { if (leveltime % 3 != 0) @@ -25,31 +33,64 @@ void Obj_SpawnEmeraldSparks(mobj_t *mobj) sparkle->sprzoff = mobj->sprzoff; } +static INT32 get_elapsed(mobj_t *emerald) +{ + return leveltime - min((tic_t)emerald_anim_start(emerald), leveltime); +} + +static INT32 get_revolve_time(mobj_t *emerald) +{ + return max(1, emerald_revolution_time(emerald)); +} + +static fixed_t get_suck_factor(mobj_t *emerald) +{ + const INT32 suck_time = get_revolve_time(emerald) * 2; + + return (min(get_elapsed(emerald), suck_time) * FRACUNIT) / suck_time; +} + +static fixed_t get_current_radius(mobj_t *emerald) +{ + fixed_t s = emerald_start_radius(emerald); + fixed_t t = emerald_target_radius(emerald); + + return s + FixedMul(t - s, get_suck_factor(emerald)); +} + +static fixed_t get_bob(mobj_t *emerald) +{ + angle_t phase = get_elapsed(emerald) * ((ANGLE_MAX / get_revolve_time(emerald)) / 2); + + return FixedMul(30 * mapobjectscale, FSIN(emerald->angle + phase)); +} + +static fixed_t center_of(mobj_t *mobj) +{ + return mobj->z + (mobj->height / 2); +} + +static fixed_t get_target_z(mobj_t *emerald) +{ + fixed_t shift = FixedMul(emerald_z_shift(emerald), FRACUNIT - get_suck_factor(emerald)); + + return center_of(emerald->target) + get_bob(emerald) + shift; +} + static void Obj_EmeraldOrbitPlayer(mobj_t *emerald) { - const int kOrbitTics = 64; - const int kPhaseTics = 128; - - const fixed_t orbit_radius = 100 * mapobjectscale; - const fixed_t orbit_height = 30 * mapobjectscale; - - mobj_t *targ = emerald->target; - - angle_t a = emerald->angle; - - fixed_t x = FixedMul(orbit_radius, FCOS(a)); - fixed_t y = FixedMul(orbit_radius, FSIN(a)); - - angle_t phase = (ANGLE_MAX / kPhaseTics) * (leveltime % kPhaseTics); + fixed_t r = get_current_radius(emerald); + fixed_t x = FixedMul(r, FCOS(emerald->angle)); + fixed_t y = FixedMul(r, FSIN(emerald->angle)); P_MoveOrigin( emerald, - targ->x + x, - targ->y + y, - targ->z + targ->height + FixedMul(orbit_height, FSIN(a + phase)) + emerald->target->x + x, + emerald->target->y + y, + get_target_z(emerald) ); - emerald->angle += ANGLE_MAX / kOrbitTics; + emerald->angle += ANGLE_MAX / get_revolve_time(emerald); } void Obj_EmeraldThink(mobj_t *emerald) @@ -84,3 +125,20 @@ void Obj_EmeraldThink(mobj_t *emerald) K_BattleOvertimeKiller(emerald); } + +void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time) +{ + P_SetTarget(&emerald->target, target); + + emerald_anim_start(emerald) = leveltime; + emerald_revolution_time(emerald) = revolution_time; + + emerald_start_radius(emerald) = R_PointToDist2(target->x, target->y, emerald->x, emerald->y); + emerald_target_radius(emerald) = radius; + + emerald->angle = R_PointToAngle2(target->x, target->y, emerald->x, emerald->y); + emerald_z_shift(emerald) = emerald->z - get_target_z(emerald); + + emerald->flags |= MF_NOGRAVITY | MF_NOCLIP | MF_NOCLIPTHING | MF_NOCLIPHEIGHT; + emerald->shadowscale = 0; +} diff --git a/src/objects/ufo.c b/src/objects/ufo.c index f8e15c459..0ed90df50 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -883,7 +883,7 @@ boolean Obj_UFOEmeraldCollect(mobj_t *ufo, mobj_t *toucher) const int kScaleTics = 16; // Emerald will now orbit the player - P_SetTarget(&emerald->target, toucher); + Obj_BeginEmeraldOrbit(emerald, toucher, 100 * mapobjectscale, 64); // Scale down because the emerald is huge // Super Emerald needs to be scaled down further From dd7f6b17dd5b70edf92e14e2ba620044172a9c85 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 03:28:41 -0700 Subject: [PATCH 05/47] Add fuse behavior to emerald orbit, Battle collect animation - Battle emeralds orbit into the player's body upon collection - Emerald shrinks down to a speck - Orbiting speed increases over time - Player's emerald flags altered at the end of the animation --- src/k_objects.h | 3 +- src/objects/emerald.c | 68 +++++++++++++++++++++++++++++++++++++++++-- src/objects/ufo.c | 2 +- src/p_inter.c | 11 +++++-- src/p_mobj.c | 6 ++++ 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/k_objects.h b/src/k_objects.h index 513f88fdb..3cb031229 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -207,7 +207,8 @@ void Obj_SneakerPanelCollide(mobj_t *pad, mobj_t *mo); /* Emerald */ void Obj_SpawnEmeraldSparks(mobj_t *source); void Obj_EmeraldThink(mobj_t *emerald); -void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time); +void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse); +void Obj_GiveEmerald(mobj_t *emerald); #ifdef __cplusplus } // extern "C" diff --git a/src/objects/emerald.c b/src/objects/emerald.c index 6ef557b12..4c428ea12 100644 --- a/src/objects/emerald.c +++ b/src/objects/emerald.c @@ -4,6 +4,7 @@ #include "../m_random.h" #include "../p_local.h" #include "../r_main.h" +#include "../s_sound.h" #include "../tables.h" #define emerald_type(o) ((o)->extravalue1) @@ -12,6 +13,11 @@ #define emerald_start_radius(o) ((o)->movecount) #define emerald_target_radius(o) ((o)->extravalue2) #define emerald_z_shift(o) ((o)->reactiontime) +#define emerald_scale_rate(o) ((o)->movefactor) + +// Think of this like EMERALD_SPEED_UP / EMERALD_SPEED_UP_RATE +#define EMERALD_SPEED_UP (1) // speed up by this much... +#define EMERALD_SPEED_UP_RATE (1) // ...every N tics void Obj_SpawnEmeraldSparks(mobj_t *mobj) { @@ -60,7 +66,10 @@ static fixed_t get_current_radius(mobj_t *emerald) static fixed_t get_bob(mobj_t *emerald) { - angle_t phase = get_elapsed(emerald) * ((ANGLE_MAX / get_revolve_time(emerald)) / 2); + // With a fuse, the emerald experiences "speed up" and the + // scale also shrinks. All of these these effects caused + // the bob phase shift to look disproportioned. + angle_t phase = emerald->fuse ? 0 : get_elapsed(emerald) * ((ANGLE_MAX / get_revolve_time(emerald)) / 2); return FixedMul(30 * mapobjectscale, FSIN(emerald->angle + phase)); } @@ -77,6 +86,27 @@ static fixed_t get_target_z(mobj_t *emerald) return center_of(emerald->target) + get_bob(emerald) + shift; } +static void speed_up(mobj_t *emerald) +{ + // Revolution time shouldn't decrease below zero. + if (emerald_revolution_time(emerald) <= EMERALD_SPEED_UP) + { + return; + } + + if (get_elapsed(emerald) % EMERALD_SPEED_UP_RATE) + { + return; + } + + // Decrease the fuse proportionally to the revolution time. + const fixed_t ratio = (emerald->fuse * FRACUNIT) / emerald_revolution_time(emerald); + + emerald_revolution_time(emerald) -= EMERALD_SPEED_UP; + + emerald->fuse = max(1, (emerald_revolution_time(emerald) * ratio) / FRACUNIT); +} + static void Obj_EmeraldOrbitPlayer(mobj_t *emerald) { fixed_t r = get_current_radius(emerald); @@ -91,6 +121,13 @@ static void Obj_EmeraldOrbitPlayer(mobj_t *emerald) ); emerald->angle += ANGLE_MAX / get_revolve_time(emerald); + + if (emerald->fuse > 0) + { + speed_up(emerald); + + P_InstaScale(emerald, emerald->fuse * emerald_scale_rate(emerald)); + } } void Obj_EmeraldThink(mobj_t *emerald) @@ -126,7 +163,7 @@ void Obj_EmeraldThink(mobj_t *emerald) K_BattleOvertimeKiller(emerald); } -void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time) +void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse) { P_SetTarget(&emerald->target, target); @@ -136,9 +173,36 @@ void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT3 emerald_start_radius(emerald) = R_PointToDist2(target->x, target->y, emerald->x, emerald->y); emerald_target_radius(emerald) = radius; + emerald->fuse = fuse; + + if (fuse) + { + emerald_scale_rate(emerald) = emerald->scale / fuse; + } + emerald->angle = R_PointToAngle2(target->x, target->y, emerald->x, emerald->y); emerald_z_shift(emerald) = emerald->z - get_target_z(emerald); emerald->flags |= MF_NOGRAVITY | MF_NOCLIP | MF_NOCLIPTHING | MF_NOCLIPHEIGHT; emerald->shadowscale = 0; } + +void Obj_GiveEmerald(mobj_t *emerald) +{ + if (P_MobjWasRemoved(emerald->target)) + { + return; + } + + player_t *player = emerald->target->player; + + if (!player) + { + return; + } + + player->emeralds |= emerald_type(emerald); + K_CheckEmeralds(player); + + S_StartSound(emerald->target, emerald->info->deathsound); +} diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 0ed90df50..6a9f4bbdc 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -883,7 +883,7 @@ boolean Obj_UFOEmeraldCollect(mobj_t *ufo, mobj_t *toucher) const int kScaleTics = 16; // Emerald will now orbit the player - Obj_BeginEmeraldOrbit(emerald, toucher, 100 * mapobjectscale, 64); + Obj_BeginEmeraldOrbit(emerald, toucher, 100 * mapobjectscale, 64, 0); // Scale down because the emerald is huge // Super Emerald needs to be scaled down further diff --git a/src/p_inter.c b/src/p_inter.c index fb2a7a071..7b1e9cd2e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -464,9 +464,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (toucher->hitlag > 0) return; - player->emeralds |= special->extravalue1; - K_CheckEmeralds(player); - break; + // Emerald will now orbit the player + + { + const tic_t orbit = 2*TICRATE; + Obj_BeginEmeraldOrbit(special, toucher, toucher->radius, orbit, orbit * 20); + } + + return; case MT_SPECIAL_UFO: if (Obj_UFOEmeraldCollect(special, toucher) == false) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 47d20059b..de0e233f5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9825,6 +9825,12 @@ static boolean P_FuseThink(mobj_t *mobj) break; } + case MT_EMERALD: + { + Obj_GiveEmerald(mobj); + P_RemoveMobj(mobj); + return false; + } case MT_PLAYER: break; // don't remove default: From 4857d48633bdbef34f436bc77677b108ec6b648d Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 03:40:17 -0700 Subject: [PATCH 06/47] Add "twinkle" lens flare to emeralds - Battle: plays once the orbiting collection animation finishes and the player's emerald flags are updated - Centered on the player - Sealed Star: plays as soon as the orbiting animation begins - Centered on the emerald --- src/deh_tables.c | 3 ++ src/info.c | 29 +++++++++++++++++++ src/info.h | 3 ++ src/k_objects.h | 1 + src/objects/emerald.c | 67 +++++++++++++++++++++++++++++++++++++++++++ src/p_mobj.c | 8 ++++++ 6 files changed, 111 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 97a78e936..0196e2086 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1208,6 +1208,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_EMERALDSPARK6", "S_EMERALDSPARK7", + "S_EMERALDFLARE1", + // Emerald hunt shards "S_SHRD1", "S_SHRD2", @@ -4807,6 +4809,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_EMBLEM", "MT_EMERALD", "MT_EMERALDSPARK", + "MT_EMERALDFLARE", "MT_EMERHUNT", // Emerald Hunt "MT_EMERALDSPAWN", // Emerald spawner w/ delay diff --git a/src/info.c b/src/info.c index a3d358d7e..f21641943 100644 --- a/src/info.c +++ b/src/info.c @@ -1878,6 +1878,8 @@ state_t states[NUMSTATES] = {SPR_ESPK, FF_FULLBRIGHT|5, 3, {NULL}, 0, 0, S_EMERALDSPARK7}, // S_EMERALDSPARK6 {SPR_ESPK, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_EMERALDSPARK7 + {SPR_LENS, FF_FULLBRIGHT|FF_ADD|FF_TRANS10|FF_ANIMATE|11, 8, {NULL}, 7, 1, S_GAINAX_MID2}, // S_EMERALDFLARE1 + // Emerald hunt shards {SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1 {SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD2 @@ -8330,6 +8332,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_EMERALDFLARE + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_EMERHUNT 320, // doomednum S_SHRD1, // spawnstate diff --git a/src/info.h b/src/info.h index 9dc14922b..81e6554bc 100644 --- a/src/info.h +++ b/src/info.h @@ -2362,6 +2362,8 @@ typedef enum state S_EMERALDSPARK6, S_EMERALDSPARK7, + S_EMERALDFLARE1, + // Emerald hunt shards S_SHRD1, S_SHRD2, @@ -5996,6 +5998,7 @@ typedef enum mobj_type MT_EMBLEM, MT_EMERALD, MT_EMERALDSPARK, + MT_EMERALDFLARE, MT_EMERHUNT, // Emerald Hunt MT_EMERALDSPAWN, // Emerald spawner w/ delay diff --git a/src/k_objects.h b/src/k_objects.h index 3cb031229..79afc08cb 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -207,6 +207,7 @@ void Obj_SneakerPanelCollide(mobj_t *pad, mobj_t *mo); /* Emerald */ void Obj_SpawnEmeraldSparks(mobj_t *source); void Obj_EmeraldThink(mobj_t *emerald); +void Obj_EmeraldFlareThink(mobj_t *flare); void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse); void Obj_GiveEmerald(mobj_t *emerald); diff --git a/src/objects/emerald.c b/src/objects/emerald.c index 4c428ea12..7d70e400c 100644 --- a/src/objects/emerald.c +++ b/src/objects/emerald.c @@ -1,5 +1,6 @@ #include "../k_battle.h" #include "../k_objects.h" +#include "../k_specialstage.h" #include "../info.h" #include "../m_random.h" #include "../p_local.h" @@ -163,6 +164,70 @@ void Obj_EmeraldThink(mobj_t *emerald) K_BattleOvertimeKiller(emerald); } +void Obj_EmeraldFlareThink(mobj_t *flare) +{ + const INT32 kExtraTics = 3; + const INT32 flare_tics = states[S_EMERALDFLARE1].tics + kExtraTics; + + if (P_MobjWasRemoved(flare->target)) + { + P_RemoveMobj(flare); + return; + } + + // Target is assumed to be the emerald in orbit. When + // emerald fuse runs out, it shall update player's emerald + // flags. Time the flare animation so it ends with the + // emerald fuse. + if (!flare->fuse && flare->target->fuse > flare_tics) + { + return; + } + + if (flare->state == &states[S_INVISIBLE]) + { + // In special stages, just follow the emerald. + if (specialstageinfo.valid == false) + { + // Update target to player. We don't need to track + // the emerald anymore. + P_SetTarget(&flare->target, flare->target->target); + + if (P_MobjWasRemoved(flare->target)) + { + P_RemoveMobj(flare); + return; + } + } + + P_SetMobjState(flare, S_EMERALDFLARE1); + flare->fuse = flare_tics; + } + + // Focus on center of player. + P_SetOrigin(flare, flare->target->x, flare->target->y, center_of(flare->target)); +} + +static void spawn_lens_flare(mobj_t *emerald) +{ + mobj_t *flare = P_SpawnMobjFromMobj(emerald, 0, 0, 0, MT_EMERALDFLARE); + + P_SetTarget(&flare->target, emerald); + P_InstaScale(flare, emerald->target->scale); + + flare->color = emerald->color; + flare->colorized = true; + + flare->renderflags |= RF_ALWAYSONTOP; + + // FIXME: linkdraw doesn't work consistently, so I drew it on top of everyting (and through walls) +#if 0 + P_SetTarget(&flare->tracer, emerald->target); + flare->flags2 |= MF2_LINKDRAW; + flare->dispoffset = 1000; +#endif +} + void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse) { P_SetTarget(&emerald->target, target); @@ -185,6 +250,8 @@ void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT3 emerald->flags |= MF_NOGRAVITY | MF_NOCLIP | MF_NOCLIPTHING | MF_NOCLIPHEIGHT; emerald->shadowscale = 0; + + spawn_lens_flare(emerald); } void Obj_GiveEmerald(mobj_t *emerald) diff --git a/src/p_mobj.c b/src/p_mobj.c index de0e233f5..244be1ba3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7551,6 +7551,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_EMERALD: Obj_EmeraldThink(mobj); + if (P_MobjWasRemoved(mobj)) + { + return false; + } + break; + case MT_EMERALDFLARE: + Obj_EmeraldFlareThink(mobj); + if (P_MobjWasRemoved(mobj)) { return false; From 7d7cc04da209e5f89d4fd81f7398192662ab8385 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 03:42:31 -0700 Subject: [PATCH 07/47] Player glows with additive exposure while emerald collection lens flare plays For ease of programming, the emerald itself glows in Sealed Stars. --- src/objects/emerald.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/objects/emerald.c b/src/objects/emerald.c index 7d70e400c..fdf7449f2 100644 --- a/src/objects/emerald.c +++ b/src/objects/emerald.c @@ -164,6 +164,41 @@ void Obj_EmeraldThink(mobj_t *emerald) K_BattleOvertimeKiller(emerald); } +static mobj_t *spawn_glow(mobj_t *flare) +{ + mobj_t *targ = flare->target; + mobj_t *x = P_SpawnGhostMobj(targ); + + x->old_x = targ->old_x; + x->old_y = targ->old_y; + x->old_z = targ->old_z; + + x->fuse = 2; // this actually does last one tic + x->extravalue1 = 1; + x->extravalue2 = 0; + + x->renderflags = RF_ADD | RF_ALWAYSONTOP; + + // FIXME: linkdraw doesn't work consistently, so I drew it on top of everyting (and through walls) +#if 0 + P_SetTarget(&x->tracer, targ); + x->flags2 |= MF2_LINKDRAW; + x->dispoffset = 1000; +#endif + + return x; +} + +static mobj_t *spawn_glow_colorize(mobj_t *flare) +{ + mobj_t *x = spawn_glow(flare); + + x->color = flare->color; + x->colorized = true; + + return x; +} + void Obj_EmeraldFlareThink(mobj_t *flare) { const INT32 kExtraTics = 3; @@ -206,6 +241,14 @@ void Obj_EmeraldFlareThink(mobj_t *flare) // Focus on center of player. P_SetOrigin(flare, flare->target->x, flare->target->y, center_of(flare->target)); + + if (leveltime & 1) + { + // Stacked for more exposure + spawn_glow_colorize(flare); + spawn_glow(flare); + spawn_glow(flare); + } } static void spawn_lens_flare(mobj_t *emerald) From d06185f5a3eb83a84ed2996e62e7b3da129ed5a3 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 03:45:43 -0700 Subject: [PATCH 08/47] M_Drawer: don't draw PAUSE graphic in the Stereo menu --- src/k_menudraw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index b789a97f4..75de5be28 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -816,7 +816,13 @@ void M_Drawer(void) // draw pause pic if (paused && !demo.playback && (menuactive || cv_showhud.value)) { - M_DrawPausedText(0); + // Don't cover the Stereo player! + boolean stereo_open = menuactive && currentMenu == &MISC_SoundTestDef; + + if (stereo_open == false) + { + M_DrawPausedText(0); + } } // focus lost notification goes on top of everything, even the former everything From 5cc4b1ebad866a132a57b8350772b0e998faa44d Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 04:03:29 -0700 Subject: [PATCH 09/47] K_DropEmeraldsFromPlayer: fix after emerald orbiting changes I don't see what it was using the target for before so I'm just removing that. --- src/k_battle.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index 66e98561c..aa7a088d6 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -275,8 +275,7 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType) if ((player->emeralds & emeraldFlag) && (emeraldFlag & emeraldType)) { - mobj_t *emerald = K_SpawnChaosEmerald(player->mo->x, player->mo->y, player->mo->z, player->mo->angle - ANGLE_90, flip, emeraldFlag); - P_SetTarget(&emerald->target, player->mo); + K_SpawnChaosEmerald(player->mo->x, player->mo->y, player->mo->z, player->mo->angle - ANGLE_90, flip, emeraldFlag); player->emeralds &= ~emeraldFlag; break; // Drop only one emerald. Emerald wins are hard enough! From 9e5c9cfbd9a8cdd85839ebd8f09437e6d5006e0d Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 04:27:51 -0700 Subject: [PATCH 10/47] Instawhip: don't hop if activated in the air --- src/k_kart.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 6b06c1d8a..a9d9deb70 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7816,7 +7816,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - if (!P_MobjWasRemoved(player->whip)) + if (!P_MobjWasRemoved(player->whip) && (player->whip->flags2 & MF2_AMBUSH)) { // Linear acceleration and deceleration to a peak. // There is a constant total time to complete but the @@ -10963,6 +10963,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground) whip->fuse = INSTAWHIP_DURATION; player->flashing = max(player->flashing, INSTAWHIP_DURATION); + if (P_IsObjectOnGround(player->mo)) + { + whip->flags2 |= MF2_AMBUSH; + } + if (!K_PowerUpRemaining(player, POWERUP_BADGE)) { // Spawn in triangle formation From 2d7a224e8e25425716724ac7a11343612364e871 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 04:29:52 -0700 Subject: [PATCH 11/47] Instawhip hop: 1.5x height, slightly tweak timing --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index a9d9deb70..08e80e2cf 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7822,9 +7822,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) // There is a constant total time to complete but the // acceleration and deceleration times can be made // asymmetrical. - const fixed_t hop = 16 * mapobjectscale; + const fixed_t hop = 24 * mapobjectscale; const INT32 duration = 12; - const INT32 mid = (duration / 2) - 2; + const INT32 mid = (duration / 2) - 1; const INT32 t = (duration - mid) - player->whip->fuse; player->cameraOffset = hop - (abs(t * hop) / (t < 0 ? mid : duration - mid)); From 3282a2581b02639cf31fc89b34f2c85ba81169eb Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 04:58:55 -0700 Subject: [PATCH 12/47] Instawhip cooldown: don't flicker dark frames while whip is still out --- src/r_spritefx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_spritefx.cpp b/src/r_spritefx.cpp index 4db957880..756e0a96e 100644 --- a/src/r_spritefx.cpp +++ b/src/r_spritefx.cpp @@ -22,7 +22,7 @@ INT32 R_ThingLightLevel(mobj_t* thing) if (player) { - if (player->instaShieldCooldown && (player->rings <= 0) && (leveltime & 1)) + if (player->instaShieldCooldown && !player->whip && (player->rings <= 0) && (leveltime & 1)) { // Darken on every other frame of instawhip cooldown lightlevel -= 128; From 89c503135a5733a59fe465d7f89972486b3200d6 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 00:58:16 -0700 Subject: [PATCH 13/47] Tweak spectator vertical aiming - Decrease vertical aiming speed to match turning speed - Reduce software aiming bounds to 45 degrees - (Even) less distortion due to extreme angles --- src/g_build_ticcmd.cpp | 2 +- src/g_game.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 035bdc08a..4bb138d05 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -261,7 +261,7 @@ class TiccmdBuilder if (G_PlayerInputDown(forplayer(), gc_lookback, 0)) { - cmd->aiming -= joystickvector.yaxis; + cmd->aiming -= (joystickvector.yaxis * KART_FULLTURN) / JOYAXISRANGE; } else { diff --git a/src/g_game.c b/src/g_game.c index 550324341..b73dfda2f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -861,7 +861,7 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) INT32 limitangle; // note: the current software mode implementation doesn't have true perspective - limitangle = ANGLE_90 - ANG10; // Some viewing fun, but not too far down... + limitangle = ANGLE_45; // Some viewing fun, but not too far down... if (*aiming > limitangle) *aiming = limitangle; From 3320faec8cebecb124882d38c7ec0ad37b79340a Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:00:11 -0700 Subject: [PATCH 14/47] Interpolate view, even when paused Fixes slideshow movement with demo freecam while paused. Does not appear to jitter like texture scrollers do. --- src/d_main.c | 3 +++ src/r_main.c | 3 ++- src/r_main.h | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index cade52936..bc042c57c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -886,11 +886,14 @@ void D_SRB2Loop(void) { rendertimefrac = FRACUNIT; } + + rendertimefrac_unpaused = g_time.timefrac; } else { renderdeltatics = realtics * FRACUNIT; rendertimefrac = FRACUNIT; + rendertimefrac_unpaused = FRACUNIT; } if (interp || doDisplay) diff --git a/src/r_main.c b/src/r_main.c index 107e6684b..6cf539574 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -81,6 +81,7 @@ mobj_t *r_viewmobj; int r_splitscreen; fixed_t rendertimefrac; +fixed_t rendertimefrac_unpaused; fixed_t renderdeltatics; boolean renderisnewtic; @@ -1227,7 +1228,7 @@ R_SetupCommonFrame else newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; - R_InterpolateView(rendertimefrac); + R_InterpolateView(rendertimefrac_unpaused); } static void R_SetupAimingFrame(int s) diff --git a/src/r_main.h b/src/r_main.h index dcd496cfb..0f5560308 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -39,6 +39,8 @@ extern size_t validcount, linecount, loopcount, framecount; // The fraction of a tic being drawn (for interpolation between two tics) extern fixed_t rendertimefrac; +// Same as rendertimefrac but not suspended when the game is paused +extern fixed_t rendertimefrac_unpaused; // Evaluated delta tics for this frame (how many tics since the last frame) extern fixed_t renderdeltatics; // The current render is a new logical tic From bf14773b219206ef95ccb95a95d09532bc89ffa6 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:05:02 -0700 Subject: [PATCH 15/47] TiccmdBuilder: don't reset ticcmd while paused If there a short pause by mistake, this will prevent it from interrupting a drift, for instance. --- src/g_build_ticcmd.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 4bb138d05..a37af680c 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -361,14 +361,14 @@ public: explicit TiccmdBuilder(ticcmd_t* cmd_, INT32 realtics_, UINT8 ssplayer_) : cmd(cmd_), realtics(realtics_), ssplayer(ssplayer_), viewnum(G_PartyPosition(g_localplayers[forplayer()])) { - *cmd = {}; // blank ticcmd - - if (demo.playback) + if (paused || P_AutoPause()) { return; } - if (paused || P_AutoPause()) + *cmd = {}; // blank ticcmd + + if (demo.playback) { return; } From 5a973734d0c781b09ec2949f8aecfea3e81cdd2c Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:08:33 -0700 Subject: [PATCH 16/47] Move software shearing conditions from R_SetupFreelook into G_FinalClipAimingPitch --- src/g_game.c | 29 +++++++++++++++++++++++++++++ src/g_game.h | 1 + src/r_fps.c | 21 +-------------------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index b73dfda2f..e108861df 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -76,6 +76,10 @@ #include "discord.h" #endif +#ifdef HWRENDER +#include "hardware/hw_main.h" // for cv_glshearing +#endif + gameaction_t gameaction; gamestate_t gamestate = GS_NULL; UINT8 ultimatemode = false; @@ -871,6 +875,31 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) return (INT16)((*aiming)>>16); } +void G_FinalClipAimingPitch(INT32 *aiming, player_t *player, boolean skybox) +{ +#ifndef HWRENDER + (void)player; + (void)skybox; +#endif + + // clip it in the case we are looking a hardware 90 degrees full aiming + // (lmps, network and use F12...) + if (rendermode == render_soft +#ifdef HWRENDER + || (rendermode == render_opengl + && (cv_glshearing.value == 1 + || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))) +#endif + ) + { + G_SoftwareClipAimingPitch(aiming); + } + else + { + G_ClipAimingPitch(aiming); + } +} + static INT32 G_GetValueFromControlTable(INT32 deviceID, INT32 deadzone, INT32 *controltable) { INT32 i, failret = NO_BINDS_REACHABLE; diff --git a/src/g_game.h b/src/g_game.h index 71dd4ada8..72e9ce005 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -126,6 +126,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n); // clip the console player aiming to the view INT32 G_ClipAimingPitch(INT32 *aiming); INT16 G_SoftwareClipAimingPitch(INT32 *aiming); +void G_FinalClipAimingPitch(INT32 *aiming, player_t *player, boolean skybox); extern angle_t localangle[MAXSPLITSCREENPLAYERS]; extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed diff --git a/src/r_fps.c b/src/r_fps.c index 8f870abf2..f21d38943 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -22,9 +22,6 @@ #include "r_state.h" #include "z_zone.h" #include "console.h" // con_startup_loadprogress -#ifdef HWRENDER -#include "hardware/hw_main.h" // for cv_glshearing -#endif static CV_PossibleValue_t fpscap_cons_t[] = { #ifdef DEVELOP @@ -117,23 +114,7 @@ static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixe // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) static void R_SetupFreelook(player_t *player, boolean skybox) { -#ifndef HWRENDER - (void)player; - (void)skybox; -#endif - - // clip it in the case we are looking a hardware 90 degrees full aiming - // (lmps, network and use F12...) - if (rendermode == render_soft -#ifdef HWRENDER - || (rendermode == render_opengl - && (cv_glshearing.value == 1 - || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))) -#endif - ) - { - G_SoftwareClipAimingPitch((INT32 *)&aimingangle); - } + G_FinalClipAimingPitch((INT32 *)&aimingangle, player, skybox); centeryfrac = (viewheight/2)< Date: Mon, 14 Aug 2023 01:15:45 -0700 Subject: [PATCH 17/47] ST_overlayDrawer: hide VIEWPOINT text when using demo freecam --- src/st_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index dc4133089..c7166c414 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1171,7 +1171,7 @@ static void ST_overlayDrawer(void) { if (cv_showviewpointtext.value) { - if (!demo.title && !P_IsLocalPlayer(stplyr)) + if (!demo.title && !P_IsLocalPlayer(stplyr) && !demo.freecam) { if (!r_splitscreen) { From dbca307ad4c25a230dc94241dbdb00ae51deac6e Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:16:35 -0700 Subject: [PATCH 18/47] Fix sound handling in demo freecam - Object sounds are audible from the location of the camera - Certain HUD sounds should no longer be audible - For instance, lap complete sfx --- src/g_demo.c | 1 - src/p_local.h | 1 - src/p_user.c | 20 +++++++++----------- src/s_sound.c | 23 ++++++++--------------- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index d7f240f38..f0f7dca3f 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4129,7 +4129,6 @@ void G_StopDemo(void) demo.freecam = false; // reset democam shit too: democam.cam = NULL; - democam.soundmobj = NULL; democam.localangle = 0; democam.localaiming = 0; democam.keyboardlook = false; diff --git a/src/p_local.h b/src/p_local.h index 20ad1d5d2..5b46de49a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -135,7 +135,6 @@ struct camera_t struct demofreecam_s { camera_t *cam; // this is useful when the game is paused, notably - mobj_t *soundmobj; // mobj to play sound from, used in s_sound angle_t localangle; // keeps track of the cam angle for cmds angle_t localaiming; // ditto with aiming diff --git a/src/p_user.c b/src/p_user.c index d2f148283..991440d4b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1082,6 +1082,15 @@ boolean P_IsDisplayPlayer(player_t *player) return false; } + // Freecam still techically has a player in + // displayplayers. But since the camera is detached, it + // would be weird if sounds were heard from that player's + // perspective. + if (demo.freecam) + { + return false; + } + for (i = 0; i <= r_splitscreen; i++) // DON'T skip P1 { if (player == &players[displayplayers[i]]) @@ -3114,7 +3123,6 @@ void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; angle_t thrustangle; - mobj_t *awayviewmobj_hack; player_t *lastp; // update democam stuff with what we got here: @@ -3163,14 +3171,6 @@ void P_DemoCameraMovement(camera_t *cam) // besides freecam going inside walls sounds pretty cool on paper. } - // awayviewmobj hack; this is to prevent us from hearing sounds from the player's perspective - - awayviewmobj_hack = P_SpawnMobj(cam->x, cam->y, cam->z, MT_THOK); - awayviewmobj_hack->tics = 2; - awayviewmobj_hack->renderflags |= RF_DONTDRAW; - - democam.soundmobj = awayviewmobj_hack; - // update subsector to avoid crashes; cam->subsector = R_PointInSubsector(cam->x, cam->y); } @@ -3239,8 +3239,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall thiscam->old_angle = thiscam->angle; thiscam->old_aiming = thiscam->aiming; - democam.soundmobj = NULL; // reset this each frame, we don't want the game crashing for stupid reasons now do we - // We probably shouldn't move the camera if there is no player or player mobj somehow if (!player || !player->mo) return true; diff --git a/src/s_sound.c b/src/s_sound.c index a9e5a4656..eb6c9a2e1 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -540,11 +540,6 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) continue; } - if (i == 0 && democam.soundmobj) - { - continue; - } - if (player->awayview.tics) { listenmobj[i] = player->awayview.mobj; @@ -554,7 +549,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) listenmobj[i] = player->mo; } - if (origin && origin == listenmobj[i]) + if (origin && origin == listenmobj[i] && !demo.freecam) { itsUs = true; } @@ -827,11 +822,6 @@ void S_UpdateSounds(void) continue; } - if (i == 0 && democam.soundmobj) - { - continue; - } - if (player->awayview.tics) { listenmobj[i] = player->awayview.mobj; @@ -898,12 +888,15 @@ void S_UpdateSounds(void) { boolean itsUs = false; - for (i = r_splitscreen; i >= 0; i--) + if (!demo.freecam) { - if (c->origin != listenmobj[i]) - continue; + for (i = r_splitscreen; i >= 0; i--) + { + if (c->origin != listenmobj[i]) + continue; - itsUs = true; + itsUs = true; + } } if (itsUs == false) From fec0f1341988f71e12462d64a41fd4361382a6b4 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:40:25 -0700 Subject: [PATCH 19/47] P_DemoCameraMovement: use locally built ticcmd from G_BuildTiccmd --- src/d_clisrv.c | 5 ++ src/d_clisrv.h | 2 + src/g_build_ticcmd.cpp | 25 +++++- src/menus/transient/pause-replay.c | 1 - src/p_local.h | 1 - src/p_user.c | 140 +---------------------------- 6 files changed, 30 insertions(+), 144 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index eb493d55e..990f8401a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -561,6 +561,11 @@ void D_ResetTiccmds(void) D_Clearticcmd(textcmds[i]->tic); } +ticcmd_t *D_LocalTiccmd(UINT8 ss) +{ + return &localcmds[ss][0]; +} + void SendKick(UINT8 playernum, UINT8 msg) { UINT8 buf[2]; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 1d8c339e3..79d5c16cf 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -615,7 +615,9 @@ extern UINT8 playerconsole[MAXPLAYERS]; INT32 D_NumPlayers(void); boolean D_IsPlayerHumanAndGaming(INT32 player_number); + void D_ResetTiccmds(void); +ticcmd_t *D_LocalTiccmd(UINT8 ss); tic_t GetLag(INT32 node); UINT8 GetFreeXCmdSize(UINT8 playerid); diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index a37af680c..17ffcaf32 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -244,7 +244,7 @@ class TiccmdBuilder bool spectator_analog_input() { - if (!player()->spectator && !objectplacing) + if (!player()->spectator && !objectplacing && !demo.freecam) { return false; } @@ -361,6 +361,26 @@ public: explicit TiccmdBuilder(ticcmd_t* cmd_, INT32 realtics_, UINT8 ssplayer_) : cmd(cmd_), realtics(realtics_), ssplayer(ssplayer_), viewnum(G_PartyPosition(g_localplayers[forplayer()])) { + auto regular_input = [this] + { + analog_input(); + common_button_input(); + }; + + if (demo.freecam) + { + // freecam is controllable even while paused + + *cmd = {}; + + if (!typing_input()) + { + regular_input(); + } + + return; + } + if (paused || P_AutoPause()) { return; @@ -391,8 +411,7 @@ public: if (!overlay) { - analog_input(); - common_button_input(); + regular_input(); } cmd->angle = localangle[viewnum] >> TICCMD_REDUCE; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 52cc4b7e5..2032eccc2 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -236,7 +236,6 @@ void M_PlaybackToggleFreecam(INT32 choice) splitscreen = 0; R_ExecuteSetViewSize(); - P_InitCameraCmd(); // init camera controls if (!demo.freecam) // toggle on { demo.freecam = true; diff --git a/src/p_local.h b/src/p_local.h index 5b46de49a..c4a0d290a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -158,7 +158,6 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); void P_DemoCameraMovement(camera_t *cam); boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled); -void P_InitCameraCmd(void); boolean P_PlayerInPain(player_t *player); void P_ResetPlayer(player_t *player); diff --git a/src/p_user.c b/src/p_user.c index 991440d4b..a29347aa0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2979,146 +2979,8 @@ fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_height[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; -// Heavily simplified version of G_BuildTicCmd that only takes the local first player's control input and converts it to readable ticcmd_t -// we then throw that ticcmd garbage in the camera and make it move -// TODO: please just use the normal ticcmd function somehow - -static ticcmd_t cameracmd; - struct demofreecam_s democam; -// called by m_menu to reinit cam input every time it's toggled -void P_InitCameraCmd(void) -{ - memset(&cameracmd, 0, sizeof(ticcmd_t)); // initialize cmd -} - -static ticcmd_t *P_CameraCmd(camera_t *cam) -{ - /* - INT32 forward, axis; //i - // these ones used for multiple conditions - boolean turnleft, turnright, mouseaiming; - boolean invertmouse, lookaxis, usejoystick, kbl; - INT32 player_invert; - INT32 screen_invert; - */ - ticcmd_t *cmd = &cameracmd; - - (void)cam; - - if (!demo.playback) - return cmd; // empty cmd, no. - - /* - kbl = democam.keyboardlook; - - G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver - - mouseaiming = true; - invertmouse = cv_invertmouse.value; - lookaxis = cv_lookaxis[0].value; - - usejoystick = true; - turnright = PlayerInputDown(1, gc_turnright); - turnleft = PlayerInputDown(1, gc_turnleft); - - axis = PlayerJoyAxis(1, AXISTURN); - - if (encoremode) - { - turnright ^= turnleft; // swap these using three XORs - turnleft ^= turnright; - turnright ^= turnleft; - axis = -axis; - } - - if (axis != 0) - { - turnright = turnright || (axis > 0); - turnleft = turnleft || (axis < 0); - } - forward = 0; - - cmd->turning = 0; - - // let movement keys cancel each other out - if (turnright && !(turnleft)) - { - cmd->turning -= KART_FULLTURN; - } - else if (turnleft && !(turnright)) - { - cmd->turning += KART_FULLTURN; - } - - cmd->turning -= (mousex * 8) * (encoremode ? -1 : 1); - - axis = PlayerJoyAxis(1, AXISMOVE); - if (PlayerInputDown(1, gc_a) || (usejoystick && axis > 0)) - cmd->buttons |= BT_ACCELERATE; - axis = PlayerJoyAxis(1, AXISBRAKE); - if (PlayerInputDown(1, gc_brake) || (usejoystick && axis > 0)) - cmd->buttons |= BT_BRAKE; - axis = PlayerJoyAxis(1, AXISAIM); - if (PlayerInputDown(1, gc_aimforward) || (usejoystick && axis < 0)) - forward += MAXPLMOVE; - if (PlayerInputDown(1, gc_aimbackward) || (usejoystick && axis > 0)) - forward -= MAXPLMOVE; - - // fire with any button/key - axis = PlayerJoyAxis(1, AXISFIRE); - if (PlayerInputDown(1, gc_fire) || (usejoystick && axis > 0)) - cmd->buttons |= BT_ATTACK; - - // spectator aiming shit, ahhhh... - player_invert = invertmouse ? -1 : 1; - screen_invert = 1; // nope - - // mouse look stuff (mouse look is not the same as mouse aim) - kbl = false; - - // looking up/down - cmd->aiming += (mlooky<<19)*player_invert*screen_invert; - - axis = PlayerJoyAxis(1, AXISLOOK); - - // spring back if not using keyboard neither mouselookin' - if (!kbl && !lookaxis && !mouseaiming) - cmd->aiming = 0; - - if (PlayerInputDown(1, gc_lookup) || (axis < 0)) - { - cmd->aiming += KB_LOOKSPEED * screen_invert; - kbl = true; - } - else if (PlayerInputDown(1, gc_lookdown) || (axis > 0)) - { - cmd->aiming -= KB_LOOKSPEED * screen_invert; - kbl = true; - } - - if (PlayerInputDown(1, gc_centerview)) // No need to put a spectator limit on this one though :V - cmd->aiming = 0; - - cmd->forwardmove += (SINT8)forward; - - if (cmd->forwardmove > MAXPLMOVE) - cmd->forwardmove = MAXPLMOVE; - else if (cmd->forwardmove < -MAXPLMOVE) - cmd->forwardmove = -MAXPLMOVE; - - if (cmd->turning > KART_FULLTURN) - cmd->turning = KART_FULLTURN; - else if (cmd->turning < -KART_FULLTURN) - cmd->turning = -KART_FULLTURN; - - democam.keyboardlook = kbl; - */ - - return cmd; -} - void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; @@ -3131,7 +2993,7 @@ void P_DemoCameraMovement(camera_t *cam) democam.localaiming = cam->aiming; // first off we need to get button input - cmd = P_CameraCmd(cam); + cmd = D_LocalTiccmd(0); cam->aiming += cmd->aiming << TICCMD_REDUCE; cam->angle += cmd->turning << TICCMD_REDUCE; From 8809ab02fcbb3439edb32d626d22fa8581e1a174 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:47:37 -0700 Subject: [PATCH 20/47] democam: remove unnecessary fields --- src/g_demo.c | 3 --- src/menus/transient/pause-replay.c | 2 -- src/p_local.h | 5 ----- src/p_user.c | 7 ------- 4 files changed, 17 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index f0f7dca3f..ede754ee7 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4129,9 +4129,6 @@ void G_StopDemo(void) demo.freecam = false; // reset democam shit too: democam.cam = NULL; - democam.localangle = 0; - democam.localaiming = 0; - democam.keyboardlook = false; Z_Free(demo.skinlist); demo.skinlist = NULL; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 2032eccc2..6db7cee98 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -246,8 +246,6 @@ void M_PlaybackToggleFreecam(INT32 choice) demo.freecam = false; // reset democam vars: democam.cam = NULL; - //democam.turnheld = false; - democam.keyboardlook = false; // reset only these. localangle / aiming gets set before the cam does anything anyway } } diff --git a/src/p_local.h b/src/p_local.h index c4a0d290a..08b3293ed 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -135,11 +135,6 @@ struct camera_t struct demofreecam_s { camera_t *cam; // this is useful when the game is paused, notably - - angle_t localangle; // keeps track of the cam angle for cmds - angle_t localaiming; // ditto with aiming - boolean turnheld; // holding turn button for gradual turn speed - boolean keyboardlook; // keyboard look }; extern struct demofreecam_s democam; diff --git a/src/p_user.c b/src/p_user.c index a29347aa0..a6a5076b1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2989,20 +2989,13 @@ void P_DemoCameraMovement(camera_t *cam) // update democam stuff with what we got here: democam.cam = cam; - democam.localangle = cam->angle; - democam.localaiming = cam->aiming; - // first off we need to get button input cmd = D_LocalTiccmd(0); cam->aiming += cmd->aiming << TICCMD_REDUCE; cam->angle += cmd->turning << TICCMD_REDUCE; - democam.localangle += cmd->turning << TICCMD_REDUCE; - democam.localaiming += cmd->aiming << TICCMD_REDUCE; - cam->aiming = G_ClipAimingPitch((INT32 *)&cam->aiming); - democam.localaiming = G_ClipAimingPitch((INT32 *)&democam.localaiming); // camera movement: if (cmd->buttons & BT_ACCELERATE) From 83f02231e3ea11728079cae27953e7a851c373c2 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:50:34 -0700 Subject: [PATCH 21/47] Replace spectator movement with demo freecam --- src/g_build_ticcmd.cpp | 4 +-- src/g_demo.c | 2 -- src/menus/transient/pause-replay.c | 3 -- src/p_local.h | 8 ----- src/p_tick.c | 4 +-- src/p_user.c | 51 +++--------------------------- src/r_main.c | 16 ++++++---- 7 files changed, 18 insertions(+), 70 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 17ffcaf32..9ee6263f2 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -367,13 +367,13 @@ public: common_button_input(); }; - if (demo.freecam) + if (demo.freecam || player()->spectator) { // freecam is controllable even while paused *cmd = {}; - if (!typing_input()) + if (!typing_input() && !director_input()) { regular_input(); } diff --git a/src/g_demo.c b/src/g_demo.c index ede754ee7..7f58d289e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4127,8 +4127,6 @@ void G_StopDemo(void) singletics = false; demo.freecam = false; - // reset democam shit too: - democam.cam = NULL; Z_Free(demo.skinlist); demo.skinlist = NULL; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 6db7cee98..163a2885e 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -239,13 +239,10 @@ void M_PlaybackToggleFreecam(INT32 choice) if (!demo.freecam) // toggle on { demo.freecam = true; - democam.cam = &camera[0]; // this is rather useful } else // toggle off { demo.freecam = false; - // reset democam vars: - democam.cam = NULL; } } diff --git a/src/p_local.h b/src/p_local.h index 08b3293ed..22c593c21 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -131,14 +131,6 @@ struct camera_t angle_t old_angle, old_aiming; }; -// demo freecam or something before i commit die -struct demofreecam_s { - - camera_t *cam; // this is useful when the game is paused, notably -}; - -extern struct demofreecam_s democam; - extern camera_t camera[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_dist[MAXSPLITSCREENPLAYERS], cv_cam_still[MAXSPLITSCREENPLAYERS], cv_cam_height[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_speed[MAXSPLITSCREENPLAYERS], cv_cam_rotate[MAXSPLITSCREENPLAYERS]; diff --git a/src/p_tick.c b/src/p_tick.c index b6b470ce5..8e408e92b 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -729,8 +729,8 @@ void P_Ticker(boolean run) timeinmap = (timeinmap-1) & ~3; G_PreviewRewind(leveltime); } - else if (demo.freecam && democam.cam) // special case: allow freecam to MOVE during pause! - P_DemoCameraMovement(democam.cam); + else + P_RunChaseCameras(); // special case: allow freecam to MOVE during pause! return; } diff --git a/src/p_user.c b/src/p_user.c index a6a5076b1..cec39ee8a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2359,45 +2359,6 @@ static void P_UpdatePlayerAngle(player_t *player) } } - -// -// P_SpectatorMovement -// -// Control for spectators in multiplayer -// -static void P_SpectatorMovement(player_t *player) -{ - ticcmd_t *cmd = &player->cmd; - - P_UpdatePlayerAngle(player); - - ticruned++; - if (!(cmd->flags & TICCMD_RECEIVED)) - ticmiss++; - - if (cmd->buttons & BT_ACCELERATE) - player->mo->z += 32*mapobjectscale; - else if (cmd->buttons & BT_BRAKE) - player->mo->z -= 32*mapobjectscale; - - if (!(player->mo->flags & MF_NOCLIPHEIGHT)) - { - if (player->mo->z > player->mo->ceilingz - player->mo->height) - player->mo->z = player->mo->ceilingz - player->mo->height; - if (player->mo->z < player->mo->floorz) - player->mo->z = player->mo->floorz; - } - - player->mo->momx = player->mo->momy = player->mo->momz = 0; - if (cmd->forwardmove != 0) - { - P_Thrust(player->mo, player->mo->angle, cmd->forwardmove*mapobjectscale); - - // Quake-style flying spectators :D - player->mo->momz += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(player->aiming)); - } -} - // // P_MovePlayer void P_MovePlayer(player_t *player) @@ -2424,7 +2385,6 @@ void P_MovePlayer(player_t *player) if (player->spectator) { player->mo->eflags &= ~MFE_VERTICALFLIP; // deflip... - P_SpectatorMovement(player); return; } @@ -2979,16 +2939,12 @@ fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_height[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; -struct demofreecam_s democam; - void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; angle_t thrustangle; player_t *lastp; - // update democam stuff with what we got here: - democam.cam = cam; // first off we need to get button input cmd = D_LocalTiccmd(0); @@ -3004,7 +2960,7 @@ void P_DemoCameraMovement(camera_t *cam) cam->z -= 32*mapobjectscale; // if you hold item, you will lock on to displayplayer. (The last player you were ""f12-ing"") - if (cmd->buttons & BT_ATTACK) + if (demo.freecam && cmd->buttons & BT_ATTACK) { lastp = &players[displayplayers[0]]; // Fun fact, I was trying displayplayers[0]->mo as if it was Lua like an absolute idiot. cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y); @@ -3102,12 +3058,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL) return true; - if (demo.freecam) + if (demo.freecam || player->spectator) { P_DemoCameraMovement(thiscam); return true; } + if (paused || P_AutoPause()) + return true; + playerScale = FixedDiv(player->mo->scale, mapobjectscale); scaleDiff = playerScale - FRACUNIT; diff --git a/src/r_main.c b/src/r_main.c index 6cf539574..8a9abd36c 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1266,8 +1266,12 @@ void R_SetupFrame(int s) R_SetViewContext(VIEWCONTEXT_PLAYER1 + s); - if (player->spectator) // no spectator chasecam - chasecam = false; // force chasecam off + if (player->spectator) + { + // Free flying spectator uses demo freecam. This + // requires chasecam to be enabled. + chasecam = true; + } if (chasecam && (thiscam && !thiscam->chase)) { @@ -1293,7 +1297,7 @@ void R_SetupFrame(int s) R_SetupCommonFrame(player, r_viewmobj->subsector); } - else if (!player->spectator && chasecam) + else if (chasecam) // use outside cam view { r_viewmobj = NULL; @@ -1431,10 +1435,8 @@ boolean R_ViewpointHasChasecam(player_t *player) } } - if (player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN) + if (player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || player->spectator) chasecam = true; // force chasecam on - else if (player->spectator) // no spectator chasecam - chasecam = false; // force chasecam off return chasecam; } @@ -1447,7 +1449,7 @@ boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox) if (player->awayview.tics || skybox) return chasecam; // use outside cam view - else if (!player->spectator && chasecam) + else if (chasecam) return true; // use the player's eyes view From 0f9ceab817918d6da6230c0fc70b830b06b7c5d5 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:55:00 -0700 Subject: [PATCH 22/47] P_DemoCameraMovement: don't let A button press from menu carry over to rise camera --- src/menus/transient/pause-replay.c | 1 + src/p_local.h | 8 ++++++++ src/p_user.c | 18 ++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 163a2885e..46c0a6cfb 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -239,6 +239,7 @@ void M_PlaybackToggleFreecam(INT32 choice) if (!demo.freecam) // toggle on { demo.freecam = true; + democam.button_a_held = 2; } else // toggle off { diff --git a/src/p_local.h b/src/p_local.h index 22c593c21..06f8b9d61 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -131,6 +131,14 @@ struct camera_t angle_t old_angle, old_aiming; }; +// demo freecam or something before i commit die +struct demofreecam_s { + + UINT8 button_a_held; // A button was held since entering from menu, so don't move camera +}; + +extern struct demofreecam_s democam; + extern camera_t camera[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_dist[MAXSPLITSCREENPLAYERS], cv_cam_still[MAXSPLITSCREENPLAYERS], cv_cam_height[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_speed[MAXSPLITSCREENPLAYERS], cv_cam_rotate[MAXSPLITSCREENPLAYERS]; diff --git a/src/p_user.c b/src/p_user.c index cec39ee8a..46df9a0ad 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2939,6 +2939,8 @@ fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_height[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; +struct demofreecam_s democam; + void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; @@ -2954,10 +2956,18 @@ void P_DemoCameraMovement(camera_t *cam) cam->aiming = G_ClipAimingPitch((INT32 *)&cam->aiming); // camera movement: - if (cmd->buttons & BT_ACCELERATE) - cam->z += 32*mapobjectscale; - else if (cmd->buttons & BT_BRAKE) - cam->z -= 32*mapobjectscale; + if (!democam.button_a_held) + { + if (cmd->buttons & BT_ACCELERATE) + cam->z += 32*mapobjectscale; + else if (cmd->buttons & BT_BRAKE) + cam->z -= 32*mapobjectscale; + } + + if (!(cmd->buttons & BT_ACCELERATE) && democam.button_a_held) + { + democam.button_a_held--; + } // if you hold item, you will lock on to displayplayer. (The last player you were ""f12-ing"") if (demo.freecam && cmd->buttons & BT_ATTACK) From ff447a212a51b37a9a2e7369c6710f3ed46684bf Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:58:47 -0700 Subject: [PATCH 23/47] P_DemoCameraMovement: even out vertical angle after toggling After turning on freecam, the vertical angle is tilted slightly downward (this is carried over from normal chasecam). Interpolate that angle back to normal while moving forward. This makes it so you don't need to manually adjust the vertical angle, since it would cause forward movement to send you into the ground. --- src/menus/transient/pause-replay.c | 1 + src/p_local.h | 1 + src/p_user.c | 55 +++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 46c0a6cfb..fba7ec7ed 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -240,6 +240,7 @@ void M_PlaybackToggleFreecam(INT32 choice) { demo.freecam = true; democam.button_a_held = 2; + democam.reset_aiming = true; } else // toggle off { diff --git a/src/p_local.h b/src/p_local.h index 06f8b9d61..919c73dec 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -135,6 +135,7 @@ struct camera_t struct demofreecam_s { UINT8 button_a_held; // A button was held since entering from menu, so don't move camera + boolean reset_aiming; // camera aiming needs to be reset from chase camera }; extern struct demofreecam_s democam; diff --git a/src/p_user.c b/src/p_user.c index 46df9a0ad..e13a247e7 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2947,21 +2947,33 @@ void P_DemoCameraMovement(camera_t *cam) angle_t thrustangle; player_t *lastp; + boolean moving = false; + // first off we need to get button input cmd = D_LocalTiccmd(0); - cam->aiming += cmd->aiming << TICCMD_REDUCE; - cam->angle += cmd->turning << TICCMD_REDUCE; + if (cmd->aiming != 0) + { + cam->aiming += cmd->aiming << TICCMD_REDUCE; - cam->aiming = G_ClipAimingPitch((INT32 *)&cam->aiming); + democam.reset_aiming = false; + } + + cam->angle += cmd->turning << TICCMD_REDUCE; // camera movement: if (!democam.button_a_held) { if (cmd->buttons & BT_ACCELERATE) + { cam->z += 32*mapobjectscale; + moving = true; + } else if (cmd->buttons & BT_BRAKE) + { cam->z -= 32*mapobjectscale; + moving = true; + } } if (!(cmd->buttons & BT_ACCELERATE) && democam.button_a_held) @@ -2975,8 +2987,39 @@ void P_DemoCameraMovement(camera_t *cam) lastp = &players[displayplayers[0]]; // Fun fact, I was trying displayplayers[0]->mo as if it was Lua like an absolute idiot. cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y); cam->aiming = R_PointToAngle2(0, cam->z, R_PointToDist2(cam->x, cam->y, lastp->mo->x, lastp->mo->y), lastp->mo->z + lastp->mo->scale*128*P_MobjFlip(lastp->mo)); // This is still unholy. Aim a bit above their heads. + + democam.reset_aiming = false; } + if (cmd->forwardmove != 0) + { + moving = true; + } + + // After switching to democam, the vertical angle of + // chasecam is inherited. This is intentional because it + // creates a smooth transition. However, moving + // forward/back will have a slope. So, as long as democam + // controls haven't been used to alter the vertical angle, + // slowly reset it to flat. + if (democam.reset_aiming && moving) + { + INT32 aiming = cam->aiming; + INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); + + if (abs(smooth) < abs(aiming)) + { + cam->aiming -= smooth * intsign(aiming); + } + else + { + cam->aiming = 0; + democam.reset_aiming = false; // completely smoothed out + } + } + + G_FinalClipAimingPitch((INT32 *)&cam->aiming, NULL, false); + cam->momx = cam->momy = cam->momz = 0; if (cmd->forwardmove != 0) @@ -2985,7 +3028,11 @@ void P_DemoCameraMovement(camera_t *cam) cam->x += FixedMul(cmd->forwardmove*mapobjectscale, FINECOSINE(thrustangle)); cam->y += FixedMul(cmd->forwardmove*mapobjectscale, FINESINE(thrustangle)); - cam->z += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(cam->aiming)); + + if (!democam.reset_aiming) + { + cam->z += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(cam->aiming)); + } // momentums are useless here, directly add to the coordinates // this.......... doesn't actually check for floors and walls and whatnot but the function to do that is a pure mess so fuck that. From 697e42cecd9ad35f7d8c494fe6807228541d8bc9 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 02:00:46 -0700 Subject: [PATCH 24/47] P_DemoCameraMovement: drift button resets vertical angle --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index e13a247e7..97b6aefde 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3002,7 +3002,7 @@ void P_DemoCameraMovement(camera_t *cam) // forward/back will have a slope. So, as long as democam // controls haven't been used to alter the vertical angle, // slowly reset it to flat. - if (democam.reset_aiming && moving) + if ((democam.reset_aiming && moving) || (cmd->buttons & BT_DRIFT)) { INT32 aiming = cam->aiming; INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); From fcc35c1bb1f1302fe534be7f40cd2921ad633461 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 04:17:01 -0700 Subject: [PATCH 25/47] Toggle between freecam and director using C button --- src/g_build_ticcmd.cpp | 17 ++++++++++++++++- src/k_hud.c | 10 +++++++++- src/menus/transient/pause-replay.c | 11 +---------- src/p_local.h | 1 + src/p_mobj.c | 9 +++++++++ src/p_user.c | 18 ++++++++++++++++-- 6 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 9ee6263f2..5c2abee86 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -206,9 +206,17 @@ class TiccmdBuilder return true; } + void toggle_freecam_input() + { + if (M_MenuButtonPressed(forplayer(), MBT_C)) + { + P_ToggleDemoCamera(); + } + } + bool director_input() { - if (G_IsPartyLocal(displayplayers[forplayer()]) == true) + if (demo.freecam || G_IsPartyLocal(displayplayers[forplayer()]) == true) { return false; } @@ -239,6 +247,8 @@ class TiccmdBuilder } } + toggle_freecam_input(); + return true; } @@ -376,6 +386,11 @@ public: if (!typing_input() && !director_input()) { regular_input(); + + if (demo.freecam) + { + toggle_freecam_input(); + } } return; diff --git a/src/k_hud.c b/src/k_hud.c index 0d928db0c..73caf2d96 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5192,12 +5192,15 @@ static void K_drawDirectorHUD(void) offs = 2; } + K_DrawDirectorButton(offs + 1, "Freecam", kp_button_c[0], 0); + if (p == -1 || !playeringame[p] || players[p].spectator == false) { return; } - K_DrawDirectorButton(offs + 1, "Director", kp_button_r, + // TODO: this is too close to the screen bottom + K_DrawDirectorButton(offs + 2, "Director", kp_button_r, (directorinfo.active ? V_YELLOWMAP : 0)); if (players[p].flashing) @@ -5643,6 +5646,11 @@ void K_drawKartHUD(void) if (stplyr->karthud[khud_trickcool]) K_drawTrickCool(); + if (freecam) + { + K_DrawDirectorButton(3, "Freecam", kp_button_c[0], 0); + } + if (modeattacking || freecam) // everything after here is MP and debug only return; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index fba7ec7ed..68b4859dc 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -236,16 +236,7 @@ void M_PlaybackToggleFreecam(INT32 choice) splitscreen = 0; R_ExecuteSetViewSize(); - if (!demo.freecam) // toggle on - { - demo.freecam = true; - democam.button_a_held = 2; - democam.reset_aiming = true; - } - else // toggle off - { - demo.freecam = false; - } + P_ToggleDemoCamera(); } void M_PlaybackQuit(INT32 choice) diff --git a/src/p_local.h b/src/p_local.h index 919c73dec..b4bd09c51 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -154,6 +154,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); void P_DemoCameraMovement(camera_t *cam); boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled); +void P_ToggleDemoCamera(void); boolean P_PlayerInPain(player_t *player); void P_ResetPlayer(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 47d20059b..ddcce4818 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11969,6 +11969,15 @@ void P_SpawnPlayer(INT32 playernum) { K_ToggleDirector(players[consoleplayer].spectator && pcount > 0); } + + // TODO: handle splitscreen + // Spectators can switch to freecam. This should be + // disabled when they enter the race, or when the level + // changes. + if (playernum == consoleplayer && !demo.playback) + { + demo.freecam = false; + } } void P_AfterPlayerSpawn(INT32 playernum) diff --git a/src/p_user.c b/src/p_user.c index 97b6aefde..caec26b99 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2976,7 +2976,7 @@ void P_DemoCameraMovement(camera_t *cam) } } - if (!(cmd->buttons & BT_ACCELERATE) && democam.button_a_held) + if (!(cmd->buttons & (BT_ACCELERATE | BT_DRIFT)) && democam.button_a_held) { democam.button_a_held--; } @@ -3002,7 +3002,7 @@ void P_DemoCameraMovement(camera_t *cam) // forward/back will have a slope. So, as long as democam // controls haven't been used to alter the vertical angle, // slowly reset it to flat. - if ((democam.reset_aiming && moving) || (cmd->buttons & BT_DRIFT)) + if ((democam.reset_aiming && moving) || ((cmd->buttons & BT_DRIFT) && !democam.button_a_held)) { INT32 aiming = cam->aiming; INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); @@ -3043,6 +3043,20 @@ void P_DemoCameraMovement(camera_t *cam) cam->subsector = R_PointInSubsector(cam->x, cam->y); } +void P_ToggleDemoCamera(void) +{ + if (!demo.freecam) // toggle on + { + demo.freecam = true; + democam.button_a_held = 2; + democam.reset_aiming = true; + } + else // toggle off + { + demo.freecam = false; + } +} + void P_ResetCamera(player_t *player, camera_t *thiscam) { tic_t tries = 0; From c7bd74c6613abbd4c37bccb3523b5058a80bb868 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 04:38:12 -0700 Subject: [PATCH 26/47] Let replays use director controls --- src/g_build_ticcmd.cpp | 7 +------ src/k_hud.c | 5 +++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 5c2abee86..1057595b9 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -377,7 +377,7 @@ public: common_button_input(); }; - if (demo.freecam || player()->spectator) + if (demo.playback || demo.freecam || player()->spectator) { // freecam is controllable even while paused @@ -403,11 +403,6 @@ public: *cmd = {}; // blank ticcmd - if (demo.playback) - { - return; - } - if (gamestate == GS_LEVEL && player()->playerstate == PST_REBORN) { return; diff --git a/src/k_hud.c b/src/k_hud.c index 73caf2d96..569304485 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5169,7 +5169,8 @@ static void K_DrawDirectorButton(INT32 idx, const char *label, patch_t *kp[2], I static void K_drawDirectorHUD(void) { - const INT32 p = G_PartyMember(consoleplayer, R_GetViewNumber()); + const UINT8 viewnum = R_GetViewNumber(); + const INT32 p = viewnum < G_PartySize(consoleplayer) ? G_PartyMember(consoleplayer, viewnum) : -1; const char *itemtxt = "Join"; UINT8 offs = 0; @@ -5667,7 +5668,7 @@ void K_drawKartHUD(void) K_drawKartPowerUps(); - if (G_IsPartyLocal(displayplayers[viewnum]) == false && !demo.playback) + if (G_IsPartyLocal(displayplayers[viewnum]) == false) { K_drawDirectorHUD(); } From 01e2a26689b550d86975978343ea537053e9f82e Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 05:05:21 -0700 Subject: [PATCH 27/47] DEVELOP: let us spectate or pause the game at all times TODO: This should be available as a debugging option at release, since it would be useful for addon authors. I don't want to make more cvars, those are getting cluttered and should maybe be coalesced into a single debugging option. --- src/d_netcmd.c | 6 ++++++ src/g_game.c | 4 ++++ src/k_battle.c | 3 +++ src/p_inter.c | 8 ++++++++ src/p_mobj.c | 3 +++ 5 files changed, 24 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 68abb753f..f49647810 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3690,11 +3690,14 @@ static void Command_Pause(void) CONS_Printf(M_GetText("You can't pause here.\n")); return; } + // TODO: this would make a great debug feature for release +#ifndef DEVELOP else if (modeattacking) // in time attack, pausing restarts the map { //M_ModeAttackRetry(0); // directly call from m_menu; return; } +#endif SendNetXCmd(XD_PAUSE, &buf, 2); } @@ -3715,8 +3718,11 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) return; } + // TODO: this would make a great debug feature for release +#ifndef DEVELOP if (modeattacking && !demo.playback) return; +#endif paused = READUINT8(*cp); dedicatedpause = READUINT8(*cp); diff --git a/src/g_game.c b/src/g_game.c index e108861df..08fc60159 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3318,6 +3318,10 @@ boolean G_GametypeHasTeams(void) // boolean G_GametypeHasSpectators(void) { + // TODO: this would make a great debug feature for release +#ifdef DEVELOP + return true; +#endif return (netgame || (multiplayer && demo.netgame)); } diff --git a/src/k_battle.c b/src/k_battle.c index 66e98561c..837f173b4 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -127,7 +127,10 @@ void K_CheckBumpers(void) { if (nobumpers > 0 && nobumpers >= numingame) { + // TODO: this would make a great debug feature for release +#ifndef DEVELOP P_DoAllPlayersExit(PF_NOCONTEST, false); +#endif return; } } diff --git a/src/p_inter.c b/src/p_inter.c index fb2a7a071..918c3faca 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1998,7 +1998,15 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (!player->exiting && (specialstageinfo.valid == true || modeattacking & ATTACKING_SPB)) { + // TODO: this would make a great debug feature for release +#ifdef DEVELOP + if (type != DMG_SPECTATOR) + { + P_DoPlayerExit(player, PF_NOCONTEST); + } +#else P_DoPlayerExit(player, PF_NOCONTEST); +#endif } if (player->exiting) diff --git a/src/p_mobj.c b/src/p_mobj.c index ddcce4818..e3abdee26 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11841,7 +11841,10 @@ void P_SpawnPlayer(INT32 playernum) } else // Otherwise, never spectator. { + // TODO: this would make a great debug feature for release +#ifndef DEVELOP p->spectator = false; +#endif } } From 00360065864e5d7693107c09e29f19c98c00ca73 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 15 Aug 2023 01:15:56 -0700 Subject: [PATCH 28/47] R_ViewRollAngle: don't apply camera tilting while using freecam --- src/r_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.c b/src/r_main.c index 8a9abd36c..d50c43644 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -979,7 +979,7 @@ angle_t R_ViewRollAngle(const player_t *player) if (cv_tilting.value) { - if (!player->spectator) + if (!player->spectator && !demo.freecam) { roll += player->tilt; } From 414d6f3647ce905ff61ead9c7142b149f107f8cc Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 17:38:24 -0700 Subject: [PATCH 29/47] Don't reset camera position when spectating Fixes a software renderer crash due to hitlag VFX from the player's death (death from spectating) being too close to the camera. --- src/p_mobj.c | 11 +++++++---- src/p_setup.c | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index e3abdee26..ab0d25e5e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12014,12 +12014,15 @@ void P_AfterPlayerSpawn(INT32 playernum) p->drawangle = mobj->angle; - for (i = 0; i <= r_splitscreen; i++) + if (p->spectator == false) { - if (camera[i].chase) + for (i = 0; i <= r_splitscreen; i++) { - if (displayplayers[i] == playernum) - P_ResetCamera(p, &camera[i]); + if (camera[i].chase) + { + if (displayplayers[i] == playernum) + P_ResetCamera(p, &camera[i]); + } } } diff --git a/src/p_setup.c b/src/p_setup.c index 3f9bfcd2e..48caf293a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7735,6 +7735,8 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) cam->subsector = R_PointInSubsector(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) } } + + cam->chase = false; // tell camera to reset its position next tic } static void P_InitCamera(void) From 7a1e61d722aed94c87340a35d646fcf986a17f86 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 17:39:41 -0700 Subject: [PATCH 30/47] Move democam.reset_aiming to camera_t, let spectator camera even out aiming --- src/p_local.h | 4 +++- src/p_user.c | 14 ++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index b4bd09c51..a09caf896 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -126,6 +126,9 @@ struct camera_t // SRB2Kart: camera pitches on slopes angle_t pitch; + // Freecam: aiming needs to be reset after switching from chasecam + boolean reset_aiming; + // Interpolation data fixed_t old_x, old_y, old_z; angle_t old_angle, old_aiming; @@ -135,7 +138,6 @@ struct camera_t struct demofreecam_s { UINT8 button_a_held; // A button was held since entering from menu, so don't move camera - boolean reset_aiming; // camera aiming needs to be reset from chase camera }; extern struct demofreecam_s democam; diff --git a/src/p_user.c b/src/p_user.c index caec26b99..df58dc55f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2956,7 +2956,7 @@ void P_DemoCameraMovement(camera_t *cam) { cam->aiming += cmd->aiming << TICCMD_REDUCE; - democam.reset_aiming = false; + cam->reset_aiming = false; } cam->angle += cmd->turning << TICCMD_REDUCE; @@ -2988,7 +2988,7 @@ void P_DemoCameraMovement(camera_t *cam) cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y); cam->aiming = R_PointToAngle2(0, cam->z, R_PointToDist2(cam->x, cam->y, lastp->mo->x, lastp->mo->y), lastp->mo->z + lastp->mo->scale*128*P_MobjFlip(lastp->mo)); // This is still unholy. Aim a bit above their heads. - democam.reset_aiming = false; + cam->reset_aiming = false; } if (cmd->forwardmove != 0) @@ -3002,7 +3002,7 @@ void P_DemoCameraMovement(camera_t *cam) // forward/back will have a slope. So, as long as democam // controls haven't been used to alter the vertical angle, // slowly reset it to flat. - if ((democam.reset_aiming && moving) || ((cmd->buttons & BT_DRIFT) && !democam.button_a_held)) + if ((cam->reset_aiming && moving) || ((cmd->buttons & BT_DRIFT) && !democam.button_a_held)) { INT32 aiming = cam->aiming; INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); @@ -3014,7 +3014,7 @@ void P_DemoCameraMovement(camera_t *cam) else { cam->aiming = 0; - democam.reset_aiming = false; // completely smoothed out + cam->reset_aiming = false; // completely smoothed out } } @@ -3029,7 +3029,7 @@ void P_DemoCameraMovement(camera_t *cam) cam->x += FixedMul(cmd->forwardmove*mapobjectscale, FINECOSINE(thrustangle)); cam->y += FixedMul(cmd->forwardmove*mapobjectscale, FINESINE(thrustangle)); - if (!democam.reset_aiming) + if (!cam->reset_aiming) { cam->z += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(cam->aiming)); } @@ -3049,7 +3049,7 @@ void P_ToggleDemoCamera(void) { demo.freecam = true; democam.button_a_held = 2; - democam.reset_aiming = true; + camera[0].reset_aiming = true; } else // toggle off { @@ -3093,6 +3093,8 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->radius = 20*FRACUNIT; thiscam->height = 16*FRACUNIT; + thiscam->reset_aiming = true; + while (!P_MoveChaseCamera(player,thiscam,true) && ++tries < 2*TICRATE); } From 7b9665402a2d62b74a7fff49f536097aaeeab348 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 17:03:28 -0700 Subject: [PATCH 31/47] P_ForceLocalAngle: reset ticcmd angles and localsteering For Sealed Stars, restarting the level after turning away from the spawn angle. This would slightly skew your momentum when spawning. --- src/d_clisrv.c | 10 ++++++++++ src/d_clisrv.h | 1 + src/p_user.c | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 990f8401a..53bbaf0b6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -561,6 +561,16 @@ void D_ResetTiccmds(void) D_Clearticcmd(textcmds[i]->tic); } +void D_ResetTiccmdAngle(UINT8 ss, angle_t angle) +{ + INT32 i; + + for (i = 0; i < MAXGENTLEMENDELAY; ++i) + { + localcmds[ss][i].angle = angle >> TICCMD_REDUCE; + } +} + ticcmd_t *D_LocalTiccmd(UINT8 ss) { return &localcmds[ss][0]; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 79d5c16cf..e2dd85bff 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -617,6 +617,7 @@ INT32 D_NumPlayers(void); boolean D_IsPlayerHumanAndGaming(INT32 player_number); void D_ResetTiccmds(void); +void D_ResetTiccmdAngle(UINT8 ss, angle_t angle); ticcmd_t *D_LocalTiccmd(UINT8 ss); tic_t GetLag(INT32 node); diff --git a/src/p_user.c b/src/p_user.c index f7a7967b6..c199eea76 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4689,6 +4689,22 @@ void P_ForceLocalAngle(player_t *player, angle_t angle) break; } } + + // jartha: OK, I don't really know how ticcmds work. The + // specific problem I'm trying to fix is that, on level + // load, the player angle gets reset. But the ticcmds + // copied in afterward don't match this angle, and they + // influence the player steering. + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[g_localplayers[i]]) + { + D_ResetTiccmdAngle(i, angle); + localsteering[i] = angle; + + break; + } + } } boolean P_PlayerFullbright(player_t *player) From d103d44938e6f732ca60af4d2b0c0b8ea9ab7933 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Sun, 20 Aug 2023 01:46:53 -0400 Subject: [PATCH 32/47] main.kart to bios.pk3 Turned main.kart into a .pk3, reorganized it, added new logo and extras --- src/d_main.c | 2 +- src/d_netfil.c | 2 +- src/sdl12/i_system.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index bc042c57c..76ffb1a57 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1099,7 +1099,7 @@ static void ChangeDirForUrlHandler(void) static boolean AddIWAD(void) { - char * path = va(pandf,srb2path,"main.kart"); + char * path = va(pandf,srb2path,"bios.pk3"); if (FIL_ReadFileOK(path)) { diff --git a/src/d_netfil.c b/src/d_netfil.c index 916dd75be..cb6897a8e 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1426,7 +1426,7 @@ void PT_FileFragment(void) filename = va("%s", file->filename); nameonly(filename); - if (!strcmp(filename, "main.kart") + if (!strcmp(filename, "bios.pk3") || !strcmp(filename, "gfx.pk3") || !strcmp(filename, "textures.pk3") || !strcmp(filename, "textures_general.pk3") diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 409339ded..2a6608039 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -217,7 +217,7 @@ void __set_fpscr(long); // in libgcc / kernel's startup.s? /** \brief WAD file to look for */ -#define WADKEYWORD "main.kart" +#define WADKEYWORD "bios.pk3" /** \brief holds wad path */ static char returnWadPath[256]; From 8a72f42818ad4779bfe29a8b751cb08da7ac6ddb Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 15 Aug 2023 16:40:00 -0700 Subject: [PATCH 33/47] Split G_ExitLevel into G_BeginLevelExit and G_FinishExitLevel - Save retry condition in G_BeginLevelExit - Apply condition in G_FinishExitLevel Preparation for ACS level end scripts, since the exit condition will need be known when the countdown starts, not when it ends (that'd be too late to do anything in the level). --- src/acs/call-funcs.cpp | 1 + src/d_netcmd.c | 2 +- src/doomstat.h | 7 ++ src/g_demo.c | 2 +- src/g_game.c | 168 ++++++++++++++++++++++------------------- src/g_game.h | 3 +- src/k_grandprix.c | 6 ++ src/lua_baselib.c | 3 +- src/p_saveg.c | 8 ++ src/p_setup.c | 3 + src/p_user.c | 13 +--- src/typedef.h | 1 + 12 files changed, 126 insertions(+), 91 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 747d74144..dff63f890 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -1802,6 +1802,7 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor if (argV[1] == 0) skipstats = 1; + G_BeginLevelExit(); exitcountdown = 1; if (server) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f49647810..582f3d98d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5776,7 +5776,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) if (G_GamestateUsesExitLevel() == false) return; - G_ExitLevel(); + G_FinishExitLevel(); } static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) diff --git a/src/doomstat.h b/src/doomstat.h index c4f8b37e7..01c2acfaa 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -762,8 +762,15 @@ extern UINT8 maxXtraLife; // Max extra lives from rings extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations +struct exitcondition_t +{ + boolean losing; + boolean retry; +}; + // For racing extern tic_t racecountdown, exitcountdown, musiccountdown; +extern exitcondition_t g_exit; #define DEFAULT_GRAVITY (4*FRACUNIT/5) extern fixed_t gravity; diff --git a/src/g_demo.c b/src/g_demo.c index 7f58d289e..de15625c0 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4161,7 +4161,7 @@ boolean G_CheckDemoStatus(void) I_Quit(); if (multiplayer && !demo.title) - G_ExitLevel(); + G_FinishExitLevel(); else { G_StopDemo(); diff --git a/src/g_game.c b/src/g_game.c index 08fc60159..1d4218062 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -274,6 +274,7 @@ mobj_t *hunt2; mobj_t *hunt3; tic_t racecountdown, exitcountdown, musiccountdown; // for racing +exitcondition_t g_exit; fixed_t gravity; fixed_t mapobjectscale; @@ -2927,95 +2928,108 @@ void G_AddPlayer(INT32 playernum) demo_extradata[playernum] |= DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER; // Set everything } -void G_ExitLevel(void) +void G_BeginLevelExit(void) +{ + g_exit.losing = true; + g_exit.retry = false; + + if (grandprixinfo.gp == true) + { + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator) + { + K_PlayerFinishGrandPrix(&players[i]); + } + } + } + + if (!G_GametypeUsesLives() || skipstats != 0) + { + g_exit.losing = false; // never force a retry + } + else if (specialstageinfo.valid == true || (gametyperules & GTR_BOSS)) + { + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator && !players[i].bot) + { + if (!K_IsPlayerLosing(&players[i])) + { + g_exit.losing = false; + break; + } + } + } + } + else if (grandprixinfo.gp == true && grandprixinfo.eventmode == GPEVENT_NONE) + { + g_exit.losing = (grandprixinfo.wonround != true); + } + + if (g_exit.losing) + { + // You didn't win... + + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator && !players[i].bot) + { + if (players[i].lives > 0) + { + g_exit.retry = true; + break; + } + } + } + } + + if (g_exit.losing && specialstageinfo.valid) + { + exitcountdown = TICRATE; + } + else + { + exitcountdown = raceexittime+1; + } +} + +void G_FinishExitLevel(void) { G_ResetAllDeviceRumbles(); if (gamestate == GS_LEVEL) { - UINT8 i; - boolean doretry = false; - - if (grandprixinfo.gp == true) + if (g_exit.retry) { - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator) - { - K_PlayerFinishGrandPrix(&players[i]); - } - } - } - - if (!G_GametypeUsesLives() || skipstats != 0) - ; // never force a retry - else if (specialstageinfo.valid == true || (gametyperules & GTR_BOSS)) - { - doretry = true; - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator && !players[i].bot) - { - if (!K_IsPlayerLosing(&players[i])) - { - doretry = false; - break; - } - } - } - } - else if (grandprixinfo.gp == true && grandprixinfo.eventmode == GPEVENT_NONE) - { - doretry = (grandprixinfo.wonround != true); - } - - if (doretry) - { - // You didn't win... - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator && !players[i].bot) - { - if (players[i].lives > 0) - { - break; - } - } - } - - if (i == MAXPLAYERS) - { - // GAME OVER, try again from the start! - if (grandprixinfo.gp == true - && grandprixinfo.eventmode == GPEVENT_SPECIAL) - { - // We were in a Special Stage. - // We can still progress to the podium when we game over here. - doretry = false; - } - else if (netgame) - { - ; // Restart cup here whenever we do Online GP - } - else - { - // Back to the menu with you. - G_HandleSaveLevel(true); - D_QuitNetGame(); - CL_Reset(); - D_ClearState(); - M_StartControlPanel(); - } - } - else + // Restart cup here whenever we do Online GP + if (!netgame) { // We have lives, just redo this one course. G_SetRetryFlag(); + return; } + } + else if (g_exit.losing) + { + // We were in a Special Stage. + // We can still progress to the podium when we game over here. + const boolean special = grandprixinfo.gp == true && grandprixinfo.eventmode == GPEVENT_SPECIAL; - if (doretry == true) + if (!netgame && !special) { + // Back to the menu with you. + G_HandleSaveLevel(true); + D_QuitNetGame(); + CL_Reset(); + D_ClearState(); + M_StartControlPanel(); return; } } diff --git a/src/g_game.h b/src/g_game.h index 72e9ce005..0b922b4da 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -206,7 +206,8 @@ boolean G_GametypeUsesLives(void); boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); INT16 G_SometimesGetDifferentEncore(void); -void G_ExitLevel(void); +void G_BeginLevelExit(void); +void G_FinishExitLevel(void); void G_NextLevel(void); void G_GetNextMap(void); void G_Continue(void); diff --git a/src/k_grandprix.c b/src/k_grandprix.c index dfbb65669..0d4b4b654 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -844,6 +844,12 @@ boolean K_CanChangeRules(boolean allowdemos) --------------------------------------------------*/ void K_PlayerFinishGrandPrix(player_t *player) { + if (grandprixinfo.wonround == true) + { + // This was already completed. + return; + } + if (player->exiting == false) { // You did not finish diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9af9ccd32..bd1771a89 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2869,7 +2869,8 @@ static int lib_gExitLevel(lua_State *L) // Moved this bit to G_SetCustomExitVars if (n >= 1) // Don't run the reset to defaults option lib_gSetCustomExitVars(L); - G_ExitLevel(); + G_BeginLevelExit(); + G_FinishExitLevel(); return 0; } diff --git a/src/p_saveg.c b/src/p_saveg.c index f948c7fa0..aa1f970c5 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5731,6 +5731,10 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT32(save->p, racecountdown); WRITEUINT32(save->p, exitcountdown); + // exitcondition_t + WRITEUINT8(save->p, g_exit.losing); + WRITEUINT8(save->p, g_exit.retry); + WRITEFIXED(save->p, gravity); WRITEFIXED(save->p, mapobjectscale); @@ -5906,6 +5910,10 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) racecountdown = READUINT32(save->p); exitcountdown = READUINT32(save->p); + // exitcondition_t + g_exit.losing = READUINT8(save->p); + g_exit.retry = READUINT8(save->p); + gravity = READFIXED(save->p); mapobjectscale = READFIXED(save->p); diff --git a/src/p_setup.c b/src/p_setup.c index 48caf293a..727fddb7e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7505,6 +7505,9 @@ static void P_InitLevelSettings(void) racecountdown = exitcountdown = musiccountdown = exitfadestarted = 0; curlap = bestlap = 0; // SRB2Kart + g_exit.losing = false; + g_exit.retry = false; + // Gamespeed and frantic items gamespeed = KARTSPEED_EASY; franticitems = false; diff --git a/src/p_user.c b/src/p_user.c index f7a7967b6..4129881c3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1318,19 +1318,12 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) if (P_CheckRacers() && !exitcountdown) { - if (specialout == true) - { - exitcountdown = TICRATE; - } - else - { - exitcountdown = raceexittime+1; - } + G_BeginLevelExit(); } } else if (!exitcountdown) // All other gametypes { - exitcountdown = raceexittime+1; + G_BeginLevelExit(); } if (grandprixinfo.gp == true && player->bot == false && losing == false) @@ -3777,7 +3770,7 @@ void P_DoTimeOver(player_t *player) if (!exitcountdown) { - exitcountdown = raceexittime; + G_BeginLevelExit(); } } diff --git a/src/typedef.h b/src/typedef.h index 7bbc232b6..ee15f0ab4 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -134,6 +134,7 @@ TYPEDEF (unloaded_mapheader_t); TYPEDEF (tolinfo_t); TYPEDEF (cupheader_t); TYPEDEF (unloaded_cupheader_t); +TYPEDEF (exitcondition_t); // font.h TYPEDEF (font_t); From 9b4367773cdb4f5fa0ad5ee56a95e8cf2c5da25c Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 15 Aug 2023 17:00:03 -0700 Subject: [PATCH 34/47] Add GAMEOVER ACS script type Triggered when the level ends with a losing condition and there are no extra lives. --- src/acs/interface.cpp | 16 ++++++++++++++++ src/acs/interface.h | 11 +++++++++++ src/acs/thread.hpp | 1 + src/g_game.c | 8 ++++++++ 4 files changed, 36 insertions(+) diff --git a/src/acs/interface.cpp b/src/acs/interface.cpp index bba86c3b9..4c14a8e2e 100644 --- a/src/acs/interface.cpp +++ b/src/acs/interface.cpp @@ -315,6 +315,22 @@ void ACS_RunEmeraldScript(mobj_t *mo) map->scriptStartType(ACS_ST_EMERALD, scriptInfo); } +/*-------------------------------------------------- + void ACS_RunGameOverScript(void) + + See header file for description. +--------------------------------------------------*/ +void ACS_RunGameOverScript(void) +{ + Environment *env = &ACSEnv; + + ACSVM::GlobalScope *const global = env->getGlobalScope(0); + ACSVM::HubScope *const hub = global->getHubScope(0); + ACSVM::MapScope *const map = hub->getMapScope(0); + + map->scriptStartType(ACS_ST_GAMEOVER, {}); +} + /*-------------------------------------------------- void ACS_Tick(void) diff --git a/src/acs/interface.h b/src/acs/interface.h index 206414663..5e9c9ba9f 100644 --- a/src/acs/interface.h +++ b/src/acs/interface.h @@ -179,6 +179,17 @@ void ACS_RunCatcherScript(mobj_t *mo); void ACS_RunEmeraldScript(mobj_t *mo); +/*-------------------------------------------------- + void ACS_RunGameOverScript(void); + + Runs the map's special scripts for exiting + the level, due to a losing condition and + without any extra lives to retry. +--------------------------------------------------*/ + +void ACS_RunGameOverScript(void); + + /*-------------------------------------------------- void ACS_Tick(void); diff --git a/src/acs/thread.hpp b/src/acs/thread.hpp index 3c146ddf6..561945cf0 100644 --- a/src/acs/thread.hpp +++ b/src/acs/thread.hpp @@ -42,6 +42,7 @@ enum acs_scriptType_e ACS_ST_OVERTIME = 7, // OVERTIME: Runs when Overtime starts in timed game modes. ACS_ST_UFO = 8, // UFO: Runs when the UFO Catcher is destroyed in a Special Stage. ACS_ST_EMERALD = 9, // EMERALD: Runs when the Chaos Emerald is collected in a Special Stage. + ACS_ST_GAMEOVER = 10, // GAMEOVER: Runs when the level ends due to a losing condition and no player has an extra life. }; // diff --git a/src/g_game.c b/src/g_game.c index 1d4218062..a248e4907 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2998,6 +2998,14 @@ void G_BeginLevelExit(void) { exitcountdown = raceexittime+1; } + + if (g_exit.losing) + { + if (!g_exit.retry) + { + ACS_RunGameOverScript(); + } + } } void G_FinishExitLevel(void) From 1a3ef843a586154d72951c1d1f8481499aa7a0b9 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 15 Aug 2023 17:46:44 -0700 Subject: [PATCH 35/47] acs/call-funcs.cpp: add StopLevelExit function --- src/acs/call-funcs.cpp | 14 ++++++++++++++ src/acs/call-funcs.hpp | 1 + src/acs/environment.cpp | 1 + 3 files changed, 16 insertions(+) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index dff63f890..88424cf2d 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -1857,6 +1857,20 @@ bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word return false; } +/*-------------------------------------------------- + bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Halts the level exit if it's happening. +--------------------------------------------------*/ +bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argV; + (void)argC; + + exitcountdown = 0; + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index bb9aa23b5..9c75cbed0 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -87,6 +87,7 @@ bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 78ffa2256..87ff3cdaf 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -171,6 +171,7 @@ Environment::Environment() addFuncDataACS0( 503, addCallFunc(CallFunc_SetLineRenderStyle)); addFuncDataACS0( 504, addCallFunc(CallFunc_MapWarp)); addFuncDataACS0( 505, addCallFunc(CallFunc_AddBot)); + addFuncDataACS0( 506, addCallFunc(CallFunc_StopLevelExit)); } ACSVM::Thread *Environment::allocThread() From 2ffc41b52e52b1e0a4733ec5b05e78d4c4b405f2 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 15 Aug 2023 17:50:20 -0700 Subject: [PATCH 36/47] G_MapNumber: let parse NEXTMAP --- src/g_game.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index a248e4907..569bae9a4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -806,9 +806,7 @@ const char *G_BuildMapName(INT32 map) */ INT32 G_MapNumber(const char * name) { -#ifdef NEXTMAPINSOC if (strncasecmp("NEXTMAP_", name, 8) != 0) -#endif { INT32 map; UINT32 hash = quickncasehash(name, MAXMAPLUMPNAME); @@ -827,7 +825,6 @@ INT32 G_MapNumber(const char * name) return NEXTMAP_INVALID; } -#ifdef NEXTMAPINSOC name += 8; if (strcasecmp("EVALUATION", name) == 0) @@ -836,9 +833,10 @@ INT32 G_MapNumber(const char * name) return NEXTMAP_CREDITS; if (strcasecmp("CEREMONY", name) == 0) return NEXTMAP_CEREMONY; - //if (strcasecmp("TITLE", name) == 0) + if (strcasecmp("TITLE", name) == 0) return NEXTMAP_TITLE; -#endif + + return NEXTMAP_INVALID; } /** Clips the console player's mouse aiming to the current view. From 0b9d691ad61a35d33bdb201f9ec56fe37547486d Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 20 Aug 2023 00:56:05 -0700 Subject: [PATCH 37/47] acs/call-funcs.cpp: add ExitLevel function --- src/acs/call-funcs.cpp | 30 ++++++++++++++++++++++++++++++ src/acs/call-funcs.hpp | 1 + src/acs/environment.cpp | 1 + 3 files changed, 32 insertions(+) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 88424cf2d..4103be255 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -1871,6 +1871,36 @@ bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSV return false; } +/*-------------------------------------------------- + bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Exits the level. +--------------------------------------------------*/ +bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argV; + (void)argC; + + if (exitcountdown == 1) + { + // An exit is already in progress. + return false; + } + + if (argC >= 1) + { + skipstats = (argV[0] == 0); + } + + G_BeginLevelExit(); + exitcountdown = 1; + + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index 9c75cbed0..864c0b2c8 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -88,6 +88,7 @@ bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 87ff3cdaf..1a43f1a2b 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -172,6 +172,7 @@ Environment::Environment() addFuncDataACS0( 504, addCallFunc(CallFunc_MapWarp)); addFuncDataACS0( 505, addCallFunc(CallFunc_AddBot)); addFuncDataACS0( 506, addCallFunc(CallFunc_StopLevelExit)); + addFuncDataACS0( 507, addCallFunc(CallFunc_ExitLevel)); } ACSVM::Thread *Environment::allocThread() From ba7d31945760d6a7d519efd9f056d248bf7eb5fb Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 20 Aug 2023 22:06:11 +0100 Subject: [PATCH 38/47] Make bios.pk3 consistent filename Removes all reference to main.kart, not just the obvious ones. --- src/config.h.in | 2 +- src/d_main.c | 6 +++--- src/k_menudraw.c | 2 +- src/sdl/i_system.c | 12 ++++++------ src/sdl12/i_system.c | 10 +++++----- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/config.h.in b/src/config.h.in index e08d94e12..1dd4da57d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -31,7 +31,7 @@ * Last updated 2020 / 08 / 30 - Kart v1.3 - patch.kart */ -#define ASSET_HASH_MAIN_KART "00000000000000000000000000000000" +#define ASSET_HASH_BIOS_PK3 "00000000000000000000000000000000" #define ASSET_HASH_GFX_PK3 "00000000000000000000000000000000" #define ASSET_HASH_TEXTURES_GENERAL_PK3 "00000000000000000000000000000000" #define ASSET_HASH_TEXTURES_SEGA_PK3 "00000000000000000000000000000000" diff --git a/src/d_main.c b/src/d_main.c index 76ffb1a57..9652f0d10 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1117,7 +1117,7 @@ static void IdentifyVersion(void) const char *srb2waddir = NULL; #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - // change to the directory where 'main.kart' is found + // change to the directory where 'bios.pk3' is found srb2waddir = I_LocateWad(); #endif @@ -1137,7 +1137,7 @@ static void IdentifyVersion(void) // Load the IWAD if (! AddIWAD()) { - I_Error("MAIN.KART not found! Expected in %s\n", srb2waddir); + I_Error("\"bios.pk3\" not found! Expected in %s\n", srb2waddir); } // will be overwritten in case of -cdrom or unix/win home @@ -1481,7 +1481,7 @@ void D_SRB2Main(void) #endif // Check MD5s of autoloaded files // Note: Do not add any files that ignore MD5! - W_VerifyFileMD5(mainwads, ASSET_HASH_MAIN_KART); // main.kart + W_VerifyFileMD5(mainwads, ASSET_HASH_BIOS_PK3); // bios.pk3 mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_PK3); // gfx.pk3 mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_TEXTURES_GENERAL_PK3); // textures_general.pk3 mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_TEXTURES_SEGA_PK3); // textures_segazones.pk3 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index b789a97f4..4ee9e751f 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5048,7 +5048,7 @@ void M_DrawAddons(void) m = numwadfiles-(mainwads+musicwads+1); - V_DrawCenteredString(BASEVIDWIDTH/2, y+4, (majormods ? highlightflags : V_TRANSLUCENT), va("%ld ADD-ON%s LOADED", (long)m, (m == 1) ? "" : "S")); //+2 for music, sounds, +1 for main.kart + V_DrawCenteredString(BASEVIDWIDTH/2, y+4, (majormods ? highlightflags : V_TRANSLUCENT), va("%ld ADD-ON%s LOADED", (long)m, (m == 1) ? "" : "S")); //+2 for music, sounds, +1 for bios.pk3 } #undef addonsseperation diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index aed47915d..d634aa368 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -137,7 +137,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #define UNIXBACKTRACE #endif -// Locations for searching for main.kart +// Locations for searching for bios.pk3 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #define DEFAULTWADLOCATION1 "/usr/local/share/games/RingRacers" #define DEFAULTWADLOCATION2 "/usr/local/games/RingRacers" @@ -150,7 +150,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); /** \brief WAD file to look for */ -#define WADKEYWORD "main.kart" +#define WADKEYWORD "bios.pk3" /** \brief holds wad path */ static char returnWadPath[256]; @@ -2104,7 +2104,7 @@ static void pathonly(char *s) } } -/** \brief search for main.kart in the given path +/** \brief search for bios.pk3 in the given path \param searchDir starting path @@ -2128,9 +2128,9 @@ static const char *searchWad(const char *searchDir) return NULL; } -/** \brief go through all possible paths and look for main.kart +/** \brief go through all possible paths and look for bios.pk3 - \return path to main.kart if any + \return path to bios.pk3 if any */ static const char *locateWad(void) @@ -2260,7 +2260,7 @@ const char *I_LocateWad(void) if (waddir) { - // change to the directory where we found main.kart + // change to the directory where we found bios.pk3 #if defined (_WIN32) SetCurrentDirectoryA(waddir); #else diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 2a6608039..0f633f290 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -145,7 +145,7 @@ void __set_fpscr(long); // in libgcc / kernel's startup.s? #define O_BINARY 0 #endif -// Locations for searching the main.kart +// Locations for searching the bios.pk3 #ifdef _arch_dreamcast #define DEFAULTWADLOCATION1 "/cd" #define DEFAULTWADLOCATION2 "/pc" @@ -3436,7 +3436,7 @@ static void pathonly(char *s) } } -/** \brief search for main.kart in the given path +/** \brief search for bios.pk3 in the given path \param searchDir starting path @@ -3460,9 +3460,9 @@ static const char *searchWad(const char *searchDir) return NULL; } -/** \brief go through all possible paths and look for main.kart +/** \brief go through all possible paths and look for bios.pk3 - \return path to main.kart if any + \return path to bios.pk3 if any */ static const char *locateWad(void) { @@ -3579,7 +3579,7 @@ const char *I_LocateWad(void) if (waddir) { - // change to the directory where we found main.kart + // change to the directory where we found bios.pk3 #if (defined (_WIN32) && !defined (_WIN32_WCE)) && !defined (_XBOX) SetCurrentDirectoryA(waddir); #elif !defined (_WIN32_WCE) && !defined (_PS3) From 274e72ed2dfdeb66edb65b609fccb01161fe4aed Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 20 Aug 2023 22:13:53 +0100 Subject: [PATCH 39/47] Shrink Sync Obj_CreateShrinkPohbees: Fix potential uninitialised memory being used that could cause a differing number of pobbys to spawn between client and server, causing an (extremely recoverable but still undesired) desync --- src/objects/shrink.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/objects/shrink.c b/src/objects/shrink.c index 5336630ba..e5dd2b8c6 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -789,11 +789,7 @@ void Obj_CreateShrinkPohbees(player_t *owner) pohbees[j].start = GetPohbeeStart(player->nextwaypoint); pohbees[j].end = endWaypoint; pohbees[j].lasers = 1; - - if (player->position == 1) - { - pohbees[j].first = true; - } + pohbees[j].first = (player->position == 1); numPohbees++; } @@ -801,6 +797,7 @@ void Obj_CreateShrinkPohbees(player_t *owner) for (i = 0; i < numPohbees; i++) { + // omg pobby hi!!! CreatePohbee(owner, pohbees[i].start, pohbees[i].end, pohbees[i].lasers); if (pohbees[i].first == true) From 99d9d4452b6737c40d7fe303c289b870cb498d3c Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 20 Aug 2023 14:55:54 -0700 Subject: [PATCH 40/47] Offline: intermission doesn't move automatically, skip with A button - Press A button the first time to do the card flip. - Press A button a second time to end the intermission. - Will not end literally immediately, in order to let tally sounds finish and GP progression bar animate. --- src/y_inter.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/y_inter.c b/src/y_inter.c index 391d0861b..6c980a7ee 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -71,6 +71,7 @@ static patch_t *widebgpatch = NULL; static patch_t *bgtile = NULL; // SPECTILE/SRB2BACK static patch_t *interpic = NULL; // custom picture defined in map header +#define INFINITE_TIMER (INT16_MAX) // just some arbitrarily large value that won't easily overflow static INT32 timer; static INT32 powertype = PWRLV_DISABLED; @@ -86,6 +87,16 @@ intertype_t intertype = int_none; static huddrawlist_h luahuddrawlist_intermission; +static boolean Y_CanSkipIntermission(void) +{ + if (!netgame) + { + return true; + } + + return false; +} + static void Y_UnloadData(void); // @@ -1533,6 +1544,17 @@ finalcounter: } } + if (Y_CanSkipIntermission()) + { + K_drawButton( + 2*FRACUNIT, + (BASEVIDHEIGHT - 16)*FRACUNIT, + 0, + kp_button_a[1], + M_MenuConfirmHeld(0) + ); + } + else { const INT32 tickDown = (timer + 1)/TICRATE; @@ -1578,6 +1600,46 @@ void Y_Ticker(void) LUA_HOOK(IntermissionThinker); + if (Y_CanSkipIntermission()) + { + if (M_MenuConfirmPressed(0)) + { + // If there is a roundqueue, make time for it. + // Else, end instantly on button press. + // Actually, give it a slight delay, so the "kaching" sound isn't cut off. + const tic_t end = roundqueue.size != 0 ? 3*TICRATE : TICRATE; + + if (intertic == -1) // card flip hasn't started + { + if (sorttic != -1) + { + intertic = sorttic; + } + else + { + intertic = 0; + timer = end; + } + } + else if (timer >= INFINITE_TIMER && intertic >= sorttic + 16) // card done flipping + { + const INT32 kaching = sorttic + 16 + (2*TICRATE); + + if (intertic < kaching) + { + intertic = kaching; // kaching immediately + } + + timer = end; + } + } + + if (intertic == -1) + { + return; + } + } + intertic++; // Team scramble code for team match and CTF. @@ -1590,7 +1652,7 @@ void Y_Ticker(void) P_DoTeamscrambling(); }*/ - if ((timer && !--timer) + if ((timer < INFINITE_TIMER && --timer <= 0) || (intertic == endtic)) { Y_EndIntermission(); @@ -1665,6 +1727,12 @@ void Y_Ticker(void) r++; data.jitter[data.num[q]] = 1; + // Player can skip the tally, kaching! + if (Y_CanSkipIntermission() && timer < INFINITE_TIMER) + { + data.increase[data.num[q]] = 0; + } + if (powertype != PWRLV_DISABLED) { // Power Levels @@ -1815,6 +1883,21 @@ void Y_StartIntermission(void) sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE); } + // TODO: code's a mess, I'm just making it extra clear + // that this piece of code is supposed to take priority + // over the above. :) + if (Y_CanSkipIntermission()) + { + timer = INFINITE_TIMER; // doesn't count down + + if (sorttic != -1) + { + // Will start immediately, but must be triggered. + // Needs to be TICRATE to bypass a condition in Y_Ticker. + sorttic = TICRATE; + } + } + // We couldn't display the intermission even if we wanted to. // But we still need to give the players their score bonuses, dummy. //if (dedicated) return; From dbe80ab3a29d0892946215ee721b9f1b66dd3d9f Mon Sep 17 00:00:00 2001 From: SteelT Date: Sun, 20 Aug 2023 19:43:05 -0400 Subject: [PATCH 41/47] Update Catch2 to latest version Fixes build errors related to it --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c35ff50f..d3c9be35b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,7 @@ if(SRB2_CONFIG_ENABLE_TESTS) # https://github.com/catchorg/Catch2 CPMAddPackage( NAME Catch2 - VERSION 3.1.1 + VERSION 3.4.0 GITHUB_REPOSITORY catchorg/Catch2 OPTIONS "CATCH_INSTALL_DOCS OFF" From f67c3df3ed805c4a5da9d4e8c744fa5b38a1f9c7 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 20 Aug 2023 16:46:01 -0700 Subject: [PATCH 42/47] HWR_ProjectSprite: fix rollangle for non-papersprites --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 976d210c2..580f0e0ad 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4773,7 +4773,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if (spriterotangle != 0 && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { - rollangle = R_GetRollAngle(vflip + rollangle = R_GetRollAngle(papersprite == vflip ? spriterotangle : InvAngle(spriterotangle)); rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); From 78ee9a7e0b689cee449fc94ec99122fdd646d3a0 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 20 Aug 2023 17:18:39 -0700 Subject: [PATCH 43/47] G_StartTitleCard: don't play titlecard sfx for Podium --- src/g_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_game.c b/src/g_game.c index 08fc60159..aa4241ef2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1284,6 +1284,7 @@ void G_StartTitleCard(void) ST_startTitleCard(); // play the sound + if (gamestate != GS_CEREMONY) { sfxenum_t kstart = sfx_kstart; if (K_CheckBossIntro() == true) From 2b02daca148e62e075694863974a23f9a71d9b51 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 20 Aug 2023 17:40:43 -0700 Subject: [PATCH 44/47] P_LoadLevel: don't randomize Podium music --- src/p_setup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 48caf293a..1b9542bd3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8148,7 +8148,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (K_PodiumSequence()) { // mapmusrng is set by local player position in K_ResetCeremony - P_ResetLevelMusic(); P_LoadLevelMusic(); } else if (gamestate == GS_LEVEL) From 82e9257284bfebd5a34d112eb87954bcf6c04817 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 21 Aug 2023 01:40:05 -0400 Subject: [PATCH 45/47] Fix frequent legacy GL crash that Jeck is getting This uses `gl_frontsector`, which can sometimes be NULL. --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 976d210c2..145a6b464 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -310,7 +310,7 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, pslope_t *slope, const sector_t { INT16 finallight = lightnum; - if (slope != NULL && P_ApplyLightOffsetFine(lightnum, sector)) + if (slope != NULL && sector != NULL && P_ApplyLightOffsetFine(lightnum, sector)) { finallight += slope->hwLightOffset; From 5f9f573f20671dbf10b12ce4936852e0882d2e37 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 21 Aug 2023 00:44:27 -0700 Subject: [PATCH 46/47] Remove all code related to linedef 413, Change music --- src/p_setup.c | 62 -------------------------------------- src/p_spec.c | 82 --------------------------------------------------- 2 files changed, 144 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 727fddb7e..048f0a54e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1203,46 +1203,6 @@ static void P_LoadSidedefs(UINT8 *data) sd->toptexture = sd->midtexture = sd->bottomtexture = 0; break; - case 413: // Change music - { - if (!isfrontside) - break; - - char process[8+1]; - - sd->toptexture = sd->midtexture = sd->bottomtexture = 0; - if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0') - { - M_Memcpy(process,msd->bottomtexture,8); - process[8] = '\0'; - sd->bottomtexture = get_number(process); - } - - if (!(msd->midtexture[0] == '-' && msd->midtexture[1] == '\0') || msd->midtexture[1] != '\0') - { - M_Memcpy(process,msd->midtexture,8); - process[8] = '\0'; - sd->midtexture = get_number(process); - } - - if (msd->toptexture[0] != '-' && msd->toptexture[1] != '\0') - { - sd->line->stringargs[0] = Z_Malloc(7, PU_LEVEL, NULL); - M_Memcpy(process,msd->toptexture,8); - process[8] = '\0'; - - // If they type in O_ or D_ and their music name, just shrug, - // then copy the rest instead. - if ((process[0] == 'O' || process[0] == 'D') && process[7]) - M_Memcpy(sd->line->stringargs[0], process+2, 6); - else // Assume it's a proper music name. - M_Memcpy(sd->line->stringargs[0], process, 6); - sd->line->stringargs[0][6] = '\0'; - } - - break; - } - case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; @@ -5569,28 +5529,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[3] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; lines[i].args[4] = lines[i].frontsector->ceilingheight >> FRACBITS; break; - case 413: //Change music - if (lines[i].flags & ML_NOCLIMB) - lines[i].args[1] |= TMM_ALLPLAYERS; - if (lines[i].flags & ML_SKEWTD) - lines[i].args[1] |= TMM_OFFSET; - if (lines[i].flags & ML_NOSKEW) - lines[i].args[1] |= TMM_FADE; - if (lines[i].flags & ML_BLOCKPLAYERS) - lines[i].args[1] |= TMM_NORELOAD; - if (lines[i].flags & ML_NOTBOUNCY) - lines[i].args[1] |= TMM_FORCERESET; - if (lines[i].flags & ML_MIDSOLID) - lines[i].args[1] |= TMM_NOLOOP; - if (lines[i].flags & ML_MIDPEG) - lines[i].args[1] |= TMM_NOCREDIT; - lines[i].args[2] = sides[lines[i].sidenum[0]].midtexture; - lines[i].args[3] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; - lines[i].args[4] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; - lines[i].args[5] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : 0; - lines[i].args[6] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].rowoffset >> FRACBITS : -1; - lines[i].args[7] = sides[lines[i].sidenum[0]].bottomtexture; - break; case 414: //Play sound effect lines[i].args[3] = tag; if (tag != 0) diff --git a/src/p_spec.c b/src/p_spec.c index 0d08cdcc0..5bb9131cb 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2886,88 +2886,6 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha } break; - case 413: // Change music - // FIXME: port to new music system -#if 0 - // console player only unless TMM_ALLPLAYERS is set - if ((args[1] & TMM_ALLPLAYERS) || (mo && mo->player && P_IsLocalPlayer(mo->player)) || titlemapinaction) - { - boolean musicsame = (!stringargs[0] || !stringargs[0][0] || !strnicmp(stringargs[0], S_MusicName(), 7)); - UINT16 tracknum = (UINT16)max(args[7], 0); - INT32 position = (INT32)max(args[2], 0); - UINT32 prefadems = (UINT32)max(args[3], 0); - UINT32 postfadems = (UINT32)max(args[4], 0); - UINT8 fadetarget = (UINT8)max(args[5], 0); - INT16 fadesource = (INT16)max(args[6], -1); - - // Seek offset from current song position - if (args[1] & TMM_OFFSET) - { - // adjust for loop point if subtracting - if (position < 0 && S_GetMusicLength() && - S_GetMusicPosition() > S_GetMusicLoopPoint() && - S_GetMusicPosition() + position < S_GetMusicLoopPoint()) - position = max(S_GetMusicLength() - (S_GetMusicLoopPoint() - (S_GetMusicPosition() + position)), 0); - else - position = max(S_GetMusicPosition() + position, 0); - } - - // Fade current music to target volume (if music won't be changed) - if ((args[1] & TMM_FADE) && fadetarget && musicsame) - { - // 0 fadesource means fade from current volume. - // meaning that we can't specify volume 0 as the source volume -- this starts at 1. - if (!fadesource) - fadesource = -1; - - if (!postfadems) - S_SetInternalMusicVolume(fadetarget); - else - S_FadeMusicFromVolume(fadetarget, fadesource, postfadems); - - if (position) - S_SetMusicPosition(position); - } - // Change the music and apply position/fade operations - else - { - if (!stringargs[0]) - break; - - strncpy(mapmusname, stringargs[0], 7); - mapmusname[6] = 0; - - mapmusflags = tracknum & MUSIC_TRACKMASK; - if (!(args[1] & TMM_NORELOAD)) - mapmusflags |= MUSIC_RELOADRESET; - if (args[1] & TMM_FORCERESET) - mapmusflags |= MUSIC_FORCERESET; - - mapmusposition = position; - mapmusresume = 0; - - S_ChangeMusicEx(mapmusname, mapmusflags, !(args[1] & TMM_NOLOOP), position, - !(args[1] & TMM_FADE) ? prefadems : 0, - !(args[1] & TMM_FADE) ? postfadems : 0); - - if (!(args[1] & TMM_NOCREDIT)) - S_ShowMusicCredit(); - - if ((args[1] & TMM_FADE) && fadetarget) - { - if (!postfadems) - S_SetInternalMusicVolume(fadetarget); - else - S_FadeMusicFromVolume(fadetarget, fadesource, postfadems); - } - } - - // Except, you can use the TMM_NORELOAD flag to change this behavior. - // if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. - } -#endif - break; - case 414: // Play SFX P_PlaySFX(stringargs[0] ? get_number(stringargs[0]) : sfx_None, mo, callsec, args[3], args[1], args[2]); break; From f234c47d8a8877292cfcaf413797179f6d576506 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 21 Aug 2023 01:04:19 -0700 Subject: [PATCH 47/47] ACS: add Music_Play, Music_StopAll and Music_Remap --- src/acs/call-funcs.cpp | 42 +++++++++++++++++++++++++++++++++++++++++ src/acs/call-funcs.hpp | 3 +++ src/acs/environment.cpp | 3 +++ 3 files changed, 48 insertions(+) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 4103be255..b122c9943 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -43,6 +43,7 @@ #include "../k_podium.h" #include "../k_bot.h" #include "../z_zone.h" +#include "../music.h" #include "call-funcs.hpp" @@ -1901,6 +1902,47 @@ bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W return false; } +/*-------------------------------------------------- + bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Play a tune. If it's already playing, restart from the + beginning. +--------------------------------------------------*/ +bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = thread->scopeMap; + + Music_Play(map->getString(argV[0])->str); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_MusicStopAll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Stop every tune that is currently playing. +--------------------------------------------------*/ +bool CallFunc_MusicStopAll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + Music_StopAll(); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Change the actual song lump that a tune will play. +--------------------------------------------------*/ +bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = thread->scopeMap; + + Music_Remap(map->getString(argV[0])->str, map->getString(argV[1])->str); + + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index 864c0b2c8..b67302f47 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -89,6 +89,9 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_MusicStopAll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 1a43f1a2b..bfa296485 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -173,6 +173,9 @@ Environment::Environment() addFuncDataACS0( 505, addCallFunc(CallFunc_AddBot)); addFuncDataACS0( 506, addCallFunc(CallFunc_StopLevelExit)); addFuncDataACS0( 507, addCallFunc(CallFunc_ExitLevel)); + addFuncDataACS0( 508, addCallFunc(CallFunc_MusicPlay)); + addFuncDataACS0( 509, addCallFunc(CallFunc_MusicStopAll)); + addFuncDataACS0( 510, addCallFunc(CallFunc_MusicRemap)); } ACSVM::Thread *Environment::allocThread()