From 79401a888f41eb9b2e820e30789d032e2ea02df5 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 8 Jan 2023 15:30:32 +0000 Subject: [PATCH 1/8] Do not spawn Heavy Magician box/particles, or play associated sounds, if the player is a spectator --- src/r_skins.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/r_skins.c b/src/r_skins.c index d38e7a41b..8e236904b 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -433,7 +433,7 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) SetFakePlayerSkin(player, i); - if (player->mo) + if (player->mo && player->spectator == false) { S_StartSound(player->mo, sfx_kc33); S_StartSound(player->mo, sfx_cdfm44); @@ -500,8 +500,11 @@ void ClearFakePlayerSkin(player_t* player) if ((flags & SF_IRONMAN) && !P_MobjWasRemoved(player->mo)) { SetFakePlayerSkin(player, skinid); - S_StartSound(player->mo, sfx_s3k9f); - K_SpawnMagicianParticles(player->mo, 5); + if (player->spectator == false) + { + S_StartSound(player->mo, sfx_s3k9f); + K_SpawnMagicianParticles(player->mo, 5); + } } player->fakeskin = MAXSKINS; From a4a74a7d2f2cf2c5f717c141c1ce3171d5bee930 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 8 Jan 2023 15:31:48 +0000 Subject: [PATCH 2/8] Do not continue to run thinker for MT_MAGICIANBOX if removed by running out of lifespan --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 778e65263..c3cc33297 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7976,7 +7976,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->extravalue2 == 0) { P_RemoveMobj(mobj); - break; + return false; } else if (mobj->extravalue2 < TICRATE/3) { @@ -8009,7 +8009,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->target->player->hyudorotimer) { P_RemoveMobj(mobj); - break; + return false; } else { From c18e7e6c3cf2575476d2972b5fdc598c42fe5a27 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 8 Jan 2023 15:32:20 +0000 Subject: [PATCH 3/8] K_SpawnMagicianParticles: NULL check on mo->target --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 694425773..4a4d15de0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1943,7 +1943,7 @@ void K_SpawnMagicianParticles(mobj_t *mo, int spread) INT32 i; mobj_t *target = mo->target; - if (P_MobjWasRemoved(target)) + if (!target || P_MobjWasRemoved(target)) target = mo; for (i = 0; i < 16; i++) From 1ae8a6dec5ecbcc003f810a52e59bd7729123d1c Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 15 Jan 2023 16:01:55 +0000 Subject: [PATCH 4/8] P_SpawnPlayer: Guarantee correct fake skin on player object at spawn --- src/p_mobj.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c3cc33297..5ff5aef49 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11729,7 +11729,26 @@ void P_SpawnPlayer(INT32 playernum) // set 'spritedef' override in mobj for player skins.. (see ProjectSprite) // (usefulness: when body mobj is detached from player (who respawns), // the dead body mobj retains the skin through the 'spritedef' override). - mobj->skin = &skins[p->skin]; + + // Loading skins from a player is a little more complicated, now. + { + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[p-players]].flags + : skins[p->skin].flags; + UINT32 skinid = p->skin; + + if ((skinflags & SF_IRONMAN) && (p->fakeskin != MAXSKINS)) + { + skinid = p->fakeskin; + if (demo.playback) + { + skinid = demo.skinlist[skinid].mapping; + } + } + + mobj->skin = &skins[skinid]; + } + P_SetupStateAnimation(mobj, mobj->state); mobj->health = 1; From 3c79e32516e0c822598f551fd150361493bdea2f Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 15 Jan 2023 16:08:28 +0000 Subject: [PATCH 5/8] P_KillPlayer: Use death frames from SF_IRONMAN skin, not those of the randomised skin Currently invisible for Heavy Magician, but a lot about her is nonfinal. --- src/p_inter.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 399d74918..b9a5e3285 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1926,6 +1926,21 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, break; } + if (player->spectator == false) + { + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[(player-players)]].flags + : skins[player->skin].flags; + + if (skinflags & SF_IRONMAN) + { + player->mo->skin = &skins[player->skin]; + K_SpawnMagicianParticles(player->mo, 5); + } + + player->mo->renderflags &= ~RF_DONTDRAW; + } + K_DropEmeraldsFromPlayer(player, player->emeralds); K_SetHitLagForObjects(player->mo, inflictor, MAXHITLAGTICS, true); @@ -1935,11 +1950,6 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, P_ResetPlayer(player); - if (player->spectator == false) - { - player->mo->renderflags &= ~RF_DONTDRAW; - } - P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); if (type == DMG_TIMEOVER) From 0606fb50bacd529ce500a8fcb019ef9eb2f1b40e Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 21 Jan 2023 12:58:06 +0000 Subject: [PATCH 6/8] S_StartSoundAtVolume, K_PlayPainSound, K_PlayHitEmSound: Use user skin for sounds instead of mobj skin So we'll always hear the clips we pick for Heavy Magician --- src/k_kart.c | 7 ++++--- src/s_sound.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 4a4d15de0..72ee22b5c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2515,8 +2515,8 @@ void K_PlayOvertakeSound(mobj_t *source) void K_PlayPainSound(mobj_t *source, mobj_t *other) { sfxenum_t pick = P_RandomKey(PR_VOICES, 2); // Gotta roll the RNG every time this is called for sync reasons - - sfxenum_t sfx_id = ((skin_t *)source->skin)->soundsid[S_sfx[sfx_khurt1 + pick].skinsound]; + skin_t *skin = (source->player ? &skins[source->player->skin] : ((skin_t *)source->skin)); + sfxenum_t sfx_id = skin->soundsid[S_sfx[sfx_khurt1 + pick].skinsound]; boolean alwaysHear = false; if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL) @@ -2534,7 +2534,8 @@ void K_PlayPainSound(mobj_t *source, mobj_t *other) void K_PlayHitEmSound(mobj_t *source, mobj_t *other) { - sfxenum_t sfx_id = ((skin_t *)source->skin)->soundsid[S_sfx[sfx_khitem].skinsound]; + skin_t *skin = (source->player ? &skins[source->player->skin] : ((skin_t *)source->skin)); + sfxenum_t sfx_id = skin->soundsid[S_sfx[sfx_khitem].skinsound]; boolean alwaysHear = false; if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL) diff --git a/src/s_sound.c b/src/s_sound.c index 0d3746d33..ddf072223 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -600,10 +600,11 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) sfx = &S_sfx[sfx_id]; - if (sfx->skinsound != -1 && origin && origin->skin) + if (sfx->skinsound != -1 && origin && (origin->player || origin->skin)) { // redirect player sound to the sound in the skin table - sfx_id = ((skin_t *)origin->skin)->soundsid[sfx->skinsound]; + skin_t *skin = (origin->player ? &skins[origin->player->skin] : ((skin_t *)origin->skin)); + sfx_id = skin->soundsid[sfx->skinsound]; sfx = &S_sfx[sfx_id]; } From 2e35a40b8084a59c365835affb41cef8ce02e69c Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 21 Jan 2023 14:43:54 +0000 Subject: [PATCH 7/8] SF_IRONMAN: handle randomised skin and hurt/death states differently - P_DamageMobj - Become skin temporarily to show off the hurt frames - Sets charflags, so P_PlayerThink can handle reversion - Add sparkles for losing disguise - P_KillPlayer - Sets charflags, so P_PlayerThink can handle reversion - Add extra sound for losing disguise - G_PlayerReborn - Sets charflags in not-betweenmaps case as well, so P_PlayerThink can handle reversion - P_SpawnPlayer - Use set skin for spawn again (partial revert of previously committed code) - P_PlayerThink - More specific conditions for fakeskin reversion - Not hurt, dead, or respawning (except for last part of drop) - Add sound and sparkles for reapplying disguise --- src/g_game.c | 7 ++++++- src/p_inter.c | 16 ++++++++++++++++ src/p_mobj.c | 21 +-------------------- src/p_user.c | 9 ++++++++- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 6cea62b1a..9408bca48 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2292,10 +2292,15 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) } else { + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[player]].flags + : skins[players[player].skin].flags; + fakeskin = players[player].fakeskin; kartspeed = players[player].kartspeed; kartweight = players[player].kartweight; - charflags = players[player].charflags; + + charflags = (skinflags & SF_IRONMAN) ? skinflags : players[player].charflags; } lastfakeskin = players[player].lastfakeskin; diff --git a/src/p_inter.c b/src/p_inter.c index b9a5e3285..ea0853440 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1935,7 +1935,9 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (skinflags & SF_IRONMAN) { player->mo->skin = &skins[player->skin]; + player->charflags = skinflags; K_SpawnMagicianParticles(player->mo, 5); + S_StartSound(player->mo, sfx_slip); } player->mo->renderflags &= ~RF_DONTDRAW; @@ -2281,6 +2283,20 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->glanceDir = 0; player->pflags &= ~PF_GAINAX; + if (!(player->charflags & SF_IRONMAN)) + { + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[(player-players)]].flags + : skins[player->skin].flags; + + if (skinflags & SF_IRONMAN) + { + player->mo->skin = &skins[player->skin]; + player->charflags = skinflags; + K_SpawnMagicianParticles(player->mo, 5); + } + } + switch (type) { case DMG_STING: diff --git a/src/p_mobj.c b/src/p_mobj.c index 5ff5aef49..c3cc33297 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11729,26 +11729,7 @@ void P_SpawnPlayer(INT32 playernum) // set 'spritedef' override in mobj for player skins.. (see ProjectSprite) // (usefulness: when body mobj is detached from player (who respawns), // the dead body mobj retains the skin through the 'spritedef' override). - - // Loading skins from a player is a little more complicated, now. - { - UINT32 skinflags = (demo.playback) - ? demo.skinlist[demo.currentskinid[p-players]].flags - : skins[p->skin].flags; - UINT32 skinid = p->skin; - - if ((skinflags & SF_IRONMAN) && (p->fakeskin != MAXSKINS)) - { - skinid = p->fakeskin; - if (demo.playback) - { - skinid = demo.skinlist[skinid].mapping; - } - } - - mobj->skin = &skins[skinid]; - } - + mobj->skin = &skins[p->skin]; P_SetupStateAnimation(mobj, mobj->state); mobj->health = 1; diff --git a/src/p_user.c b/src/p_user.c index cf9beeb8e..2e92229ea 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4238,11 +4238,18 @@ void P_PlayerThink(player_t *player) { if (player->charflags & SF_IRONMAN) // no fakeskin yet { - if (leveltime >= starttime && !player->exiting) + if (leveltime >= starttime + && !player->exiting + && player->mo->health > 0 + && (player->respawn.state == RESPAWNST_NONE + || (player->respawn.state == RESPAWNST_DROP && !player->respawn.timer)) + && !P_PlayerInPain(player)) { if (player->fakeskin != MAXSKINS) { SetFakePlayerSkin(player, player->fakeskin); + S_StartSound(player->mo, sfx_kc33); + K_SpawnMagicianParticles(player->mo, 5); } else if (!(gametyperules & GTR_CIRCUIT)) { From 52ce1d95fd72162468d6e3398655e5fe2d003730 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 21 Jan 2023 14:57:17 +0000 Subject: [PATCH 8/8] Additional spectator checks - P_DamageMobj - P_PlayerThink --- src/p_inter.c | 2 +- src/p_user.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index ea0853440..4e62fe0c5 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2283,7 +2283,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->glanceDir = 0; player->pflags &= ~PF_GAINAX; - if (!(player->charflags & SF_IRONMAN)) + if (player->spectator == false && !(player->charflags & SF_IRONMAN)) { UINT32 skinflags = (demo.playback) ? demo.skinlist[demo.currentskinid[(player-players)]].flags diff --git a/src/p_user.c b/src/p_user.c index 2e92229ea..f4bbd7e6f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4248,8 +4248,11 @@ void P_PlayerThink(player_t *player) if (player->fakeskin != MAXSKINS) { SetFakePlayerSkin(player, player->fakeskin); - S_StartSound(player->mo, sfx_kc33); - K_SpawnMagicianParticles(player->mo, 5); + if (player->spectator == false) + { + S_StartSound(player->mo, sfx_kc33); + K_SpawnMagicianParticles(player->mo, 5); + } } else if (!(gametyperules & GTR_CIRCUIT)) {