diff --git a/src/d_player.h b/src/d_player.h index a1247e8fe..6e810f944 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -487,6 +487,9 @@ typedef struct player_s SINT8 lastjawztarget; // (-1 to 15) - Last person you target with jawz, for playing the target switch sfx UINT8 jawztargetdelay; // (0 to 5) - Delay for Jawz target switching, to make it less twitchy + UINT8 confirmInflictor; // Player ID that dealt damage to you + UINT8 confirmInflictorDelay; // Delay before playing the sound + UINT8 trickpanel; // Trick panel state UINT8 tricktime; // Increases while you're tricking. You can't input any trick until it's reached a certain threshold fixed_t trickboostpower; // Save the rough speed multiplier. Used for upwards tricks. diff --git a/src/k_kart.c b/src/k_kart.c index bd6077a35..7a03655e8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2799,8 +2799,9 @@ void K_PlayPainSound(mobj_t *source) K_RegularVoiceTimers(source->player); } -void K_PlayHitEmSound(mobj_t *source) +void K_PlayHitEmSound(mobj_t *source, mobj_t *victim) { + const boolean victimIsLocal = (victim != NULL && P_IsDisplayPlayer(victim->player) == true); if (source->player->follower) { @@ -2809,11 +2810,24 @@ void K_PlayHitEmSound(mobj_t *source) } if (cv_kartvoices.value) - S_StartSound(source, sfx_khitem); + { + if (victimIsLocal == false) + { + S_StartSound(source, sfx_khitem); + } + } else + { S_StartSound(source, sfx_s1c9); // The only lost gameplay functionality with voices disabled + } K_RegularVoiceTimers(source->player); + + if (victimIsLocal == true) + { + victim->player->confirmInflictor = source->player - players; + victim->player->confirmInflictorDelay = TICRATE/2; + } } void K_PlayPowerGloatSound(mobj_t *source) @@ -2824,6 +2838,45 @@ void K_PlayPowerGloatSound(mobj_t *source) K_RegularVoiceTimers(source->player); } +static void K_HandleDelayedHitByEm(player_t *player) +{ + if (player->confirmInflictorDelay == 0) + { + return; + } + + player->confirmInflictorDelay--; + + if (player->confirmInflictorDelay == 0 + && P_IsDisplayPlayer(player) == true + && cv_kartvoices.value) + { + player_t *inflictor = NULL; + + if (player->confirmInflictor >= MAXPLAYERS) + { + return; + } + + if (!playeringame[player->confirmInflictor]) + { + return; + } + + inflictor = &players[player->confirmInflictor]; + if (inflictor == NULL || inflictor->spectator) + { + return; + } + + if (inflictor->mo != NULL && P_MobjWasRemoved(inflictor->mo) == false) + { + sfxenum_t sfx_id = ((skin_t *)inflictor->mo->skin)->soundsid[S_sfx[sfx_khitem].skinsound]; + S_StartSound(NULL, sfx_id); + } + } +} + void K_MomentumToFacing(player_t *player) { angle_t dangle = player->mo->angle - K_MomentumAngle(player->mo); @@ -7593,6 +7646,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { K_SpawnBrakeVisuals(player); } + + K_HandleDelayedHitByEm(player); } void K_KartPlayerAfterThink(player_t *player) diff --git a/src/k_kart.h b/src/k_kart.h index 89f176d29..c0bd71462 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -150,7 +150,7 @@ void K_PlayAttackTaunt(mobj_t *source); void K_PlayBoostTaunt(mobj_t *source); void K_PlayOvertakeSound(mobj_t *source); void K_PlayPainSound(mobj_t *source); -void K_PlayHitEmSound(mobj_t *source); +void K_PlayHitEmSound(mobj_t *source, mobj_t *victim); void K_PlayPowerGloatSound(mobj_t *source); fixed_t K_ItemScaleForPlayer(player_t *player); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 58835006d..944ab49bc 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3348,10 +3348,13 @@ static int lib_kPainSound(lua_State *L) static int lib_kHitEmSound(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *victim = NULL; NOHUD if (!mobj->player) return luaL_error(L, "K_PlayHitEmSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful. - K_PlayHitEmSound(mobj); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + victim = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + K_PlayHitEmSound(mobj, victim); return 0; } diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 506d6b96a..b4a971d99 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -356,6 +356,10 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->lastjawztarget); else if (fastcmp(field,"jawztargetdelay")) lua_pushinteger(L, plr->jawztargetdelay); + else if (fastcmp(field,"confirmInflictor")) + lua_pushinteger(L, plr->confirmInflictor); + else if (fastcmp(field,"confirmInflictorDelay")) + lua_pushinteger(L, plr->confirmInflictorDelay); else if (fastcmp(field,"glanceDir")) lua_pushinteger(L, plr->glanceDir); else if (fastcmp(field,"trickpanel")) @@ -704,6 +708,10 @@ static int player_set(lua_State *L) plr->lastjawztarget = luaL_checkinteger(L, 3); else if (fastcmp(field,"jawztargetdelay")) plr->jawztargetdelay = luaL_checkinteger(L, 3); + else if (fastcmp(field,"confirmInflictor")) + plr->confirmInflictor = luaL_checkinteger(L, 3); + else if (fastcmp(field,"confirmInflictorDelay")) + plr->confirmInflictorDelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"glanceDir")) plr->glanceDir = luaL_checkinteger(L, 3); else if (fastcmp(field,"trickpanel")) diff --git a/src/p_inter.c b/src/p_inter.c index 9e98a8808..8a4d6754c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2002,7 +2002,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da source->player->invincibilitytimer = kinvextend; } - K_PlayHitEmSound(source); + K_PlayHitEmSound(source, target); K_BattleAwardHit(source->player, player, inflictor, takeBumpers); K_TakeBumpersFromPlayer(source->player, player, takeBumpers); diff --git a/src/p_saveg.c b/src/p_saveg.c index 8e7115c3f..f6819eb9c 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -326,6 +326,9 @@ static void P_NetArchivePlayers(void) WRITESINT8(save_p, players[i].lastjawztarget); WRITEUINT8(save_p, players[i].jawztargetdelay); + WRITEUINT8(save_p, players[i].confirmInflictor); + WRITEUINT8(save_p, players[i].confirmInflictorDelay); + WRITEUINT8(save_p, players[i].trickpanel); WRITEUINT8(save_p, players[i].tricktime); WRITEUINT32(save_p, players[i].trickboostpower); @@ -599,6 +602,9 @@ static void P_NetUnArchivePlayers(void) players[i].lastjawztarget = READSINT8(save_p); players[i].jawztargetdelay = READUINT8(save_p); + players[i].confirmInflictor = READUINT8(save_p); + players[i].confirmInflictorDelay = READUINT8(save_p); + players[i].trickpanel = READUINT8(save_p); players[i].tricktime = READUINT8(save_p); players[i].trickboostpower = READUINT32(save_p); diff --git a/src/p_user.c b/src/p_user.c index b490d65dc..145835e48 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1093,6 +1093,11 @@ boolean P_IsMachineLocalPlayer(player_t *player) { UINT8 i; + if (player == NULL) + { + return false; + } + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[g_localplayers[i]]) @@ -1113,6 +1118,11 @@ boolean P_IsLocalPlayer(player_t *player) { UINT8 i; + if (player == NULL) + { + return false; + } + // nobody is ever local when watching something back - you're a spectator there, even if your g_localplayers might say otherwise if (demo.playback) return false; @@ -1141,6 +1151,11 @@ boolean P_IsDisplayPlayer(player_t *player) { UINT8 i; + if (player == NULL) + { + return false; + } + for (i = 0; i <= r_splitscreen; i++) // DON'T skip P1 { if (player == &players[displayplayers[i]])