Merge branch 'hear-pain' into 'master'

Improved MKSC-style hit confirms

See merge request KartKrew/Kart!659
This commit is contained in:
Oni 2022-09-07 04:44:03 +00:00
commit ea3818d285
7 changed files with 97 additions and 65 deletions

View file

@ -506,8 +506,8 @@ 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 confirmVictim; // Player ID that you dealt damage to
UINT8 confirmVictimDelay; // 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

View file

@ -2824,91 +2824,107 @@ void K_PlayOvertakeSound(mobj_t *source)
K_RegularVoiceTimers(source->player);
}
void K_PlayPainSound(mobj_t *source)
void K_PlayPainSound(mobj_t *source, mobj_t *other)
{
sfxenum_t pick = P_RandomKey(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];
boolean alwaysHear = false;
if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL)
{
alwaysHear = P_IsDisplayPlayer(other->player);
}
if (cv_kartvoices.value)
S_StartSound(source, sfx_khurt1 + pick);
{
S_StartSound(alwaysHear ? NULL : source, sfx_id);
}
K_RegularVoiceTimers(source->player);
}
void K_PlayHitEmSound(mobj_t *source, mobj_t *victim)
void K_PlayHitEmSound(mobj_t *source, mobj_t *other)
{
const boolean victimIsLocal = (victim != NULL && P_IsDisplayPlayer(victim->player) == true);
sfxenum_t sfx_id = ((skin_t *)source->skin)->soundsid[S_sfx[sfx_khitem].skinsound];
boolean alwaysHear = false;
if (source->player->follower)
if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL)
{
follower_t fl = followers[source->player->followerskin];
source->player->follower->movecount = fl.hitconfirmtime; // movecount is used to play the hitconfirm animation for followers.
alwaysHear = P_IsDisplayPlayer(other->player);
}
if (cv_kartvoices.value)
{
if (victimIsLocal == false)
{
S_StartSound(source, sfx_khitem);
}
}
else
{
S_StartSound(source, sfx_s1c9); // The only lost gameplay functionality with voices disabled
S_StartSound(alwaysHear ? NULL : source, sfx_id);
}
K_RegularVoiceTimers(source->player);
}
if (victim != NULL && victim->player != NULL)
void K_TryHurtSoundExchange(mobj_t *victim, mobj_t *attacker)
{
if (victim == NULL || P_MobjWasRemoved(victim) == true || victim->player == NULL)
{
victim->player->confirmInflictor = source->player - players;
victim->player->confirmInflictorDelay = TICRATE/2;
return;
}
// In a perfect world we could move this here, but there's
// a few niche situations where we want a pain sound from
// the victim, but no confirm sound from the attacker.
// (ex: DMG_STING)
//K_PlayPainSound(victim, attacker);
if (attacker == NULL || P_MobjWasRemoved(attacker) == true || attacker->player == NULL)
{
return;
}
attacker->player->confirmVictim = (victim->player - players);
attacker->player->confirmVictimDelay = TICRATE/2;
if (attacker->player->follower != NULL)
{
const follower_t *fl = &followers[attacker->player->followerskin];
attacker->player->follower->movecount = fl->hitconfirmtime; // movecount is used to play the hitconfirm animation for followers.
}
}
void K_PlayPowerGloatSound(mobj_t *source)
{
if (cv_kartvoices.value)
{
S_StartSound(source, sfx_kgloat);
}
K_RegularVoiceTimers(source->player);
}
static void K_HandleDelayedHitByEm(player_t *player)
{
if (player->confirmInflictorDelay == 0)
if (player->confirmVictimDelay == 0)
{
return;
}
player->confirmInflictorDelay--;
player->confirmVictimDelay--;
if (player->confirmInflictorDelay == 0
&& P_IsDisplayPlayer(player) == true
&& cv_kartvoices.value)
if (player->confirmVictimDelay == 0)
{
player_t *inflictor = NULL;
mobj_t *victim = NULL;
if (player->confirmInflictor >= MAXPLAYERS)
if (player->confirmVictim < MAXPLAYERS && playeringame[player->confirmVictim])
{
return;
player_t *victimPlayer = &players[player->confirmVictim];
if (victimPlayer != NULL && victimPlayer->spectator == false)
{
victim = victimPlayer->mo;
}
}
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);
}
K_PlayHitEmSound(player->mo, victim);
}
}

View file

@ -154,8 +154,9 @@ void K_HandleDirectionalInfluence(player_t *player);
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, mobj_t *victim);
void K_PlayPainSound(mobj_t *source, mobj_t *other);
void K_PlayHitEmSound(mobj_t *source, mobj_t *other);
void K_TryHurtSoundExchange(mobj_t *victim, mobj_t *attacker);
void K_PlayPowerGloatSound(mobj_t *source);
fixed_t K_ItemScaleForPlayer(player_t *player);

View file

@ -3339,23 +3339,37 @@ static int lib_kOvertakeSound(lua_State *L)
static int lib_kPainSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *other = NULL;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayPainSound: 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_PlayPainSound(mobj);
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayPainSound(mobj, other);
return 0;
}
static int lib_kHitEmSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *victim = NULL;
mobj_t *other = 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.
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
victim = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayHitEmSound(mobj, victim);
other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayHitEmSound(mobj, other);
return 0;
}
static int lib_kTryHurtSoundExchange(lua_State *L)
{
mobj_t *victim = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *attacker = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
if (!victim->player)
return luaL_error(L, "K_TryHurtSoundExchange: 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_TryHurtSoundExchange(victim, attacker);
return 0;
}
@ -4037,6 +4051,7 @@ static luaL_Reg lib[] = {
{"K_PlayLossSound", lib_kLossSound},
{"K_PlayPainSound", lib_kPainSound},
{"K_PlayHitEmSound", lib_kHitEmSound},
{"K_TryHurtSoundExchange", lib_kTryHurtSoundExchange},
{"K_IsPlayerLosing",lib_kIsPlayerLosing},
{"K_IsPlayerWanted",lib_kIsPlayerWanted},
{"K_KartBouncing",lib_kKartBouncing},

View file

@ -362,10 +362,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,"confirmVictim"))
lua_pushinteger(L, plr->confirmVictim);
else if (fastcmp(field,"confirmVictimDelay"))
lua_pushinteger(L, plr->confirmVictimDelay);
else if (fastcmp(field,"glanceDir"))
lua_pushinteger(L, plr->glanceDir);
else if (fastcmp(field,"trickpanel"))
@ -722,10 +722,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,"confirmVictim"))
plr->confirmVictim = luaL_checkinteger(L, 3);
else if (fastcmp(field,"confirmVictimDelay"))
plr->confirmVictimDelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"glanceDir"))
plr->glanceDir = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickpanel"))

View file

@ -2012,7 +2012,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
source->player->invincibilitytimer += kinvextend;
}
K_PlayHitEmSound(source, target);
K_TryHurtSoundExchange(target, source);
K_BattleAwardHit(source->player, player, inflictor, takeBumpers);
K_TakeBumpersFromPlayer(source->player, player, takeBumpers);
@ -2085,14 +2085,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->flashing = K_GetKartFlashing(player);
}
P_PlayRinglossSound(player->mo);
P_PlayRinglossSound(target);
if (ringburst > 0)
{
P_PlayerRingBurst(player, ringburst);
}
K_PlayPainSound(player->mo);
K_PlayPainSound(target, source);
if ((hardhit == true) || (cv_kartdebughuddrop.value && !modeattacking))
{

View file

@ -339,8 +339,8 @@ 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].confirmVictim);
WRITEUINT8(save_p, players[i].confirmVictimDelay);
WRITEUINT8(save_p, players[i].trickpanel);
WRITEUINT8(save_p, players[i].tricktime);
@ -626,8 +626,8 @@ 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].confirmVictim = READUINT8(save_p);
players[i].confirmVictimDelay = READUINT8(save_p);
players[i].trickpanel = READUINT8(save_p);
players[i].tricktime = READUINT8(save_p);