mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
P_DamageMobjCompat
This commit is contained in:
parent
55b333e01f
commit
4478fce917
1 changed files with 802 additions and 0 deletions
802
src/p_inter.c
802
src/p_inter.c
|
|
@ -2855,6 +2855,805 @@ static boolean P_FlashingException(const player_t *player, const mobj_t *inflict
|
|||
return true;
|
||||
}
|
||||
|
||||
static boolean P_DamageMobjCompat(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
player_t *player;
|
||||
player_t *playerInflictor;
|
||||
boolean force = false;
|
||||
boolean spbpop = false;
|
||||
boolean downgraded = false;
|
||||
|
||||
INT32 laglength = 6;
|
||||
|
||||
if (objectplacing)
|
||||
return false;
|
||||
|
||||
if (target->health <= 0)
|
||||
return false;
|
||||
|
||||
// Spectator handling
|
||||
if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator)
|
||||
return false;
|
||||
|
||||
// source is checked without a removal guard in so many places that it's genuinely less work to do it here.
|
||||
if (source && P_MobjWasRemoved(source))
|
||||
source = NULL;
|
||||
|
||||
if (source && source->player && source->player->spectator)
|
||||
return false;
|
||||
|
||||
if (((damagetype & DMG_TYPEMASK) == DMG_STING)
|
||||
|| ((inflictor && !P_MobjWasRemoved(inflictor)) && inflictor->type == MT_BANANA && inflictor->health <= 1))
|
||||
{
|
||||
laglength = 2;
|
||||
}
|
||||
else if (target->type == MT_DROPTARGET || target->type == MT_DROPTARGET_SHIELD)
|
||||
{
|
||||
laglength = 0; // handled elsewhere
|
||||
}
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_MONITOR:
|
||||
damage = Obj_MonitorGetDamage(target, inflictor, damagetype);
|
||||
Obj_MonitorOnDamage(target, inflictor, damage);
|
||||
break;
|
||||
case MT_CDUFO:
|
||||
// Make it possible to pick them up during race
|
||||
if (inflictor->type == MT_ORBINAUT_SHIELD || inflictor->type == MT_JAWZ_SHIELD)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case MT_SPB:
|
||||
spbpop = (damagetype & DMG_TYPEMASK) == DMG_VOLTAGE;
|
||||
if (spbpop && source && source->player
|
||||
&& source->player->roundconditions.spb_neuter == false)
|
||||
{
|
||||
source->player->roundconditions.spb_neuter = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything above here can't be forced.
|
||||
{
|
||||
UINT8 shouldForce = LUA_HookShouldDamage(target, inflictor, source, damage, damagetype);
|
||||
if (P_MobjWasRemoved(target))
|
||||
return (shouldForce == 1); // mobj was removed
|
||||
if (shouldForce == 1)
|
||||
force = true;
|
||||
else if (shouldForce == 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_BALLSWITCH_BALL:
|
||||
Obj_BallSwitchDamaged(target, inflictor, source);
|
||||
return false;
|
||||
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
return Obj_TryCrateDamage(target, inflictor);
|
||||
|
||||
case MT_KART_LEFTOVER:
|
||||
// intangible (do not let instawhip shred damage)
|
||||
if (Obj_DestroyKart(target))
|
||||
return false;
|
||||
|
||||
P_SetObjectMomZ(target, 12*FRACUNIT, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if (!spbpop)
|
||||
{
|
||||
if (!(target->flags & MF_SHOOTABLE))
|
||||
return false; // shouldn't happen...
|
||||
}
|
||||
}
|
||||
|
||||
if (target->flags2 & MF2_SKULLFLY)
|
||||
target->momx = target->momy = target->momz = 0;
|
||||
|
||||
if (target->flags & (MF_ENEMY|MF_BOSS))
|
||||
{
|
||||
if (!force && target->flags2 & MF2_FRET) // Currently flashing from being hit
|
||||
return false;
|
||||
|
||||
if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
return true;
|
||||
|
||||
if (target->health > 1)
|
||||
target->flags2 |= MF2_FRET;
|
||||
}
|
||||
|
||||
player = target->player;
|
||||
playerInflictor = inflictor ? inflictor->player : NULL;
|
||||
|
||||
if (playerInflictor)
|
||||
{
|
||||
AddTimesHit(playerInflictor);
|
||||
}
|
||||
|
||||
if (player) // Player is the target
|
||||
{
|
||||
AddTimesHit(player);
|
||||
|
||||
if (player->pflags & PF_GODMODE)
|
||||
return false;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
// Player hits another player
|
||||
if (source && source->player)
|
||||
{
|
||||
if (!P_PlayerHitsPlayer(target, inflictor, source, damage, damagetype))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (source && source->player)
|
||||
{
|
||||
if (source->player->roundconditions.hit_midair == false
|
||||
&& source != target
|
||||
&& inflictor
|
||||
&& K_IsMissileOrKartItem(inflictor)
|
||||
&& target->player->airtime > TICRATE/2
|
||||
&& source->player->airtime > TICRATE/2)
|
||||
{
|
||||
source->player->roundconditions.hit_midair = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
|
||||
if (source->player->roundconditions.hit_drafter_lookback == false
|
||||
&& source != target
|
||||
&& target->player->lastdraft == (source->player - players)
|
||||
&& (K_GetKartButtons(source->player) & BT_LOOKBACK) == BT_LOOKBACK
|
||||
/*&& (AngleDelta(K_MomentumAngle(source), R_PointToAngle2(source->x, source->y, target->x, target->y)) > ANGLE_90)*/)
|
||||
{
|
||||
source->player->roundconditions.hit_drafter_lookback = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
|
||||
if (source->player->roundconditions.giant_foe_shrunken_orbi == false
|
||||
&& source != target
|
||||
&& player->growshrinktimer > 0
|
||||
&& !P_MobjWasRemoved(inflictor)
|
||||
&& inflictor->type == MT_ORBINAUT
|
||||
&& inflictor->scale < FixedMul((FRACUNIT + SHRINK_SCALE), mapobjectscale * 2)) // halfway between base scale and shrink scale, a little bit of leeway
|
||||
{
|
||||
source->player->roundconditions.giant_foe_shrunken_orbi = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
|
||||
if (source == target
|
||||
&& !P_MobjWasRemoved(inflictor)
|
||||
&& inflictor->type == MT_SPBEXPLOSION
|
||||
&& inflictor->threshold == KITEM_EGGMAN
|
||||
&& !P_MobjWasRemoved(inflictor->tracer)
|
||||
&& inflictor->tracer != source
|
||||
&& inflictor->tracer->player
|
||||
&& inflictor->tracer->player->roundconditions.returntosender_mark == false)
|
||||
{
|
||||
inflictor->tracer->player->roundconditions.returntosender_mark = true;
|
||||
inflictor->tracer->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
}
|
||||
else if (!(inflictor && inflictor->player)
|
||||
&& !(player->exiting || player->laps > numlaps)
|
||||
&& damagetype != DMG_DEATHPIT)
|
||||
{
|
||||
// laps will never increment outside of GTR_CIRCUIT, so this is still fine
|
||||
const UINT8 requiredbit = 1<<(player->laps & 7);
|
||||
|
||||
if (!(player->roundconditions.hittrackhazard[player->laps/8] & requiredbit))
|
||||
{
|
||||
player->roundconditions.hittrackhazard[player->laps/8] |= requiredbit;
|
||||
player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Instant-Death
|
||||
if ((damagetype & DMG_DEATHMASK))
|
||||
{
|
||||
if (!P_KillPlayer(player, inflictor, source, damagetype))
|
||||
return false;
|
||||
}
|
||||
else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 type = (damagetype & DMG_TYPEMASK);
|
||||
const boolean hardhit = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can do evil stuff like ALWAYS combo
|
||||
INT16 ringburst = 5;
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
if (!force)
|
||||
{
|
||||
boolean invincible = true;
|
||||
boolean clash = false;
|
||||
sfxenum_t sfx = sfx_None;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Gametype does not have bumpers, steal damage is intended to not do anything
|
||||
// (No instashield is intentional)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
sfx = sfx_invind;
|
||||
}
|
||||
else if (K_IsBigger(target, inflictor) == true &&
|
||||
// SPB bypasses grow (K_IsBigger handles NULL check)
|
||||
(type != DMG_EXPLODE || inflictor->type != MT_SPBEXPLOSION || !inflictor->movefactor))
|
||||
{
|
||||
sfx = sfx_grownd;
|
||||
}
|
||||
else if (K_PlayerGuard(player))
|
||||
{
|
||||
sfx = sfx_s3k3a;
|
||||
clash = true;
|
||||
}
|
||||
else if (player->overshield &&
|
||||
(type != DMG_EXPLODE || inflictor->type != MT_SPBEXPLOSION || !inflictor->movefactor))
|
||||
{
|
||||
clash = true;
|
||||
}
|
||||
else if (player->hyudorotimer > 0)
|
||||
;
|
||||
else
|
||||
{
|
||||
invincible = false;
|
||||
}
|
||||
|
||||
// Hack for instawhip-guard counter, lets invincible players lose to guard
|
||||
if (inflictor == target)
|
||||
{
|
||||
invincible = false;
|
||||
}
|
||||
|
||||
if (player->pflags2 & PF2_ALWAYSDAMAGED)
|
||||
{
|
||||
invincible = false;
|
||||
clash = false;
|
||||
}
|
||||
|
||||
// TODO: doing this from P_DamageMobj limits punting to objects that damage the player.
|
||||
// And it may be kind of yucky.
|
||||
// But this is easier than accounting for every condition in PIT_CheckThing!
|
||||
if (inflictor && K_PuntCollide(inflictor, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (invincible && type != DMG_WHUMBLE)
|
||||
{
|
||||
const INT32 oldHitlag = target->hitlag;
|
||||
const INT32 oldHitlagInflictor = inflictor ? inflictor->hitlag : 0;
|
||||
|
||||
// Damage during hitlag should be a no-op
|
||||
// for invincibility states because there
|
||||
// are no flashing tics. If the damage is
|
||||
// from a constant source, a deadlock
|
||||
// would occur.
|
||||
|
||||
if (target->eflags & MFE_PAUSED)
|
||||
{
|
||||
player->timeshit--; // doesn't count
|
||||
|
||||
if (playerInflictor)
|
||||
{
|
||||
playerInflictor->timeshit--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
laglength = max(laglength / 2, 1);
|
||||
K_SetHitLagForObjects(target, inflictor, source, laglength, false);
|
||||
|
||||
AddNullHitlag(player, oldHitlag);
|
||||
AddNullHitlag(playerInflictor, oldHitlagInflictor);
|
||||
|
||||
if (player->timeshit > player->timeshitprev)
|
||||
{
|
||||
S_StartSound(target, sfx);
|
||||
}
|
||||
|
||||
if (clash)
|
||||
{
|
||||
player->spheres = max(player->spheres - 5, 0);
|
||||
|
||||
if (inflictor)
|
||||
{
|
||||
K_DoPowerClash(target, inflictor);
|
||||
|
||||
if (inflictor->type == MT_SUPER_FLICKY)
|
||||
{
|
||||
Obj_BlockSuperFlicky(inflictor);
|
||||
}
|
||||
}
|
||||
else if (source)
|
||||
K_DoPowerClash(target, source);
|
||||
}
|
||||
|
||||
// Full invulnerability
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
{
|
||||
// Check if we should allow wombo combos (hard hits by default, inverted by the presence of DMG_WOMBO).
|
||||
boolean allowcombo = ((hardhit || (type == DMG_STUMBLE || type == DMG_WHUMBLE)) == !(damagetype & DMG_WOMBO));
|
||||
|
||||
// Tumble/stumble is a special case.
|
||||
if (type == DMG_TUMBLE)
|
||||
{
|
||||
// don't allow constant combo
|
||||
if (player->tumbleBounces == 1 && (P_MobjFlip(target)*target->momz > 0))
|
||||
allowcombo = false;
|
||||
}
|
||||
else if (type == DMG_STUMBLE || type == DMG_WHUMBLE)
|
||||
{
|
||||
// don't allow constant combo
|
||||
if (player->tumbleBounces == TUMBLEBOUNCES-1 && (P_MobjFlip(target)*target->momz > 0))
|
||||
{
|
||||
if (type == DMG_STUMBLE)
|
||||
return false; // No-sell strings of stumble
|
||||
|
||||
allowcombo = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->momx == 0 && inflictor->momy == 0 && inflictor->momz == 0)
|
||||
{
|
||||
// Probably a map hazard.
|
||||
allowcombo = false;
|
||||
}
|
||||
|
||||
if (allowcombo == false && (target->eflags & MFE_PAUSED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout
|
||||
if ((target->hitlag == 0 || allowcombo == false) &&
|
||||
player->flashing > 0 &&
|
||||
type != DMG_EXPLODE &&
|
||||
type != DMG_STUMBLE &&
|
||||
type != DMG_WHUMBLE &&
|
||||
P_FlashingException(player, inflictor) == false)
|
||||
{
|
||||
// Post-hit invincibility
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
else if (target->flags2 & MF2_ALREADYHIT) // do not deal extra damage in the same tic
|
||||
{
|
||||
K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Steals 2 bumpers
|
||||
damage = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not die from damage outside of bumpers health system
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
boolean softenTumble = false;
|
||||
|
||||
// Sting and stumble shouldn't be rewarding Battle hits.
|
||||
if (type == DMG_STING || type == DMG_STUMBLE)
|
||||
{
|
||||
damage = 0;
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
if (!P_PlayerInPain(player) && (player->defenseLockout || player->instaWhipCharge))
|
||||
{
|
||||
K_SpawnAmps(source->player, 20, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We successfully damaged them! Give 'em some bumpers!
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
// Stone Shoe handles amps on its own, but this is also a good place to set soften tumble for it
|
||||
if (inflictor->type == MT_STONESHOE || inflictor->type == MT_STONESHOE_CHAIN)
|
||||
softenTumble = true;
|
||||
else
|
||||
K_SpawnAmps(source->player, K_PvPAmpReward((type == DMG_WHUMBLE) ? 30 : 20, source->player, player), target);
|
||||
|
||||
|
||||
K_BotHitPenalty(player);
|
||||
|
||||
if (G_SameTeam(source->player, player))
|
||||
{
|
||||
if (type != DMG_EXPLODE)
|
||||
{
|
||||
type = DMG_STUMBLE;
|
||||
downgraded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (UINT8 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || !players[i].mo || P_MobjWasRemoved(players[i].mo))
|
||||
continue;
|
||||
if (!G_SameTeam(source->player, &players[i]))
|
||||
continue;
|
||||
if (source->player == &players[i])
|
||||
continue;
|
||||
K_SpawnAmps(&players[i], FixedInt(FixedMul(5, K_TeamComebackMultiplier(player))), target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extend the invincibility if the hit was a direct hit.
|
||||
if (inflictor == source && source->player->invincibilitytimer &&
|
||||
!K_PowerUpRemaining(source->player, POWERUP_SMONITOR))
|
||||
{
|
||||
tic_t kinvextend;
|
||||
|
||||
softenTumble = true;
|
||||
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
kinvextend = 2*TICRATE;
|
||||
else
|
||||
kinvextend = 3*TICRATE;
|
||||
|
||||
// Reduce the value of subsequent invinc extensions
|
||||
kinvextend = kinvextend / (1 + source->player->invincibilityextensions); // 50%, 33%, 25%[...]
|
||||
kinvextend = max(kinvextend, TICRATE);
|
||||
|
||||
source->player->invincibilityextensions++;
|
||||
|
||||
source->player->invincibilitytimer += kinvextend;
|
||||
|
||||
if (P_IsDisplayPlayer(source->player))
|
||||
S_StartSound(NULL, sfx_gsha7);
|
||||
}
|
||||
|
||||
// if the inflictor is a landmine, its reactiontime will be non-zero if it is still moving
|
||||
if (inflictor->type == MT_LANDMINE && inflictor->reactiontime > 0)
|
||||
{
|
||||
// reduce tumble severity to account for getting beaned point blank sometimes
|
||||
softenTumble = true;
|
||||
// make it more consistent with set landmines
|
||||
inflictor->momx = 0;
|
||||
inflictor->momy = 0;
|
||||
}
|
||||
|
||||
K_TryHurtSoundExchange(target, source);
|
||||
|
||||
if (K_Cooperative() == false)
|
||||
{
|
||||
K_BattleAwardHit(source->player, player, inflictor, damage);
|
||||
}
|
||||
|
||||
if (K_Bumpers(source->player) < K_StartingBumperCount() || (damagetype & DMG_STEAL))
|
||||
{
|
||||
K_TakeBumpersFromPlayer(source->player, player, damage);
|
||||
}
|
||||
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Give them ALL of your emeralds instantly :)
|
||||
source->player->emeralds |= player->emeralds;
|
||||
player->emeralds = 0;
|
||||
K_CheckEmeralds(source->player);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(damagetype & DMG_STEAL))
|
||||
{
|
||||
// Drop all of your emeralds
|
||||
K_DropEmeraldsFromPlayer(player, player->emeralds);
|
||||
}
|
||||
}
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
if (damagetype != DMG_DEATHPIT)
|
||||
{
|
||||
player->pitblame = source->player - players;
|
||||
}
|
||||
}
|
||||
|
||||
player->sneakertimer = player->numsneakers = 0;
|
||||
player->panelsneakertimer = player->numpanelsneakers = 0;
|
||||
player->weaksneakertimer = player->numweaksneakers = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
player->fastfall = 0;
|
||||
player->ringboost = 0;
|
||||
player->glanceDir = 0;
|
||||
player->preventfailsafe = TICRATE*3;
|
||||
player->pflags &= ~PF_GAINAX;
|
||||
Obj_EndBungee(player);
|
||||
K_BumperInflate(target->player);
|
||||
|
||||
UINT32 hurtskinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[(player-players)]].flags
|
||||
: skins[player->skin]->flags;
|
||||
if (hurtskinflags & SF_IRONMAN)
|
||||
{
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
SetRandomFakePlayerSkin(player, false, true);
|
||||
}
|
||||
|
||||
// Explosions are explicit combo setups.
|
||||
if (damagetype & DMG_EXPLODE)
|
||||
player->bumperinflate = 0;
|
||||
|
||||
if (player->spectator == false && !(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);
|
||||
}
|
||||
}
|
||||
|
||||
if (player->rings <= -20)
|
||||
{
|
||||
player->markedfordeath = true;
|
||||
damagetype = DMG_TUMBLE;
|
||||
type = DMG_TUMBLE;
|
||||
P_StartQuakeFromMobj(5, 44 * player->mo->scale, 2560 * player->mo->scale, player->mo);
|
||||
//P_KillPlayer(player, inflictor, source, damagetype);
|
||||
}
|
||||
|
||||
// Death save! On your last hit, no matter what, demote to weakest damage type for one last escape chance.
|
||||
if (player->mo->health == 2 && damage && gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
K_AddMessageForPlayer(player, "\x8DLast Chance!", false, false);
|
||||
S_StartSound(target, sfx_gshc7);
|
||||
player->flashing = TICRATE;
|
||||
type = DMG_STUMBLE;
|
||||
}
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && P_IsKartItem(inflictor->type) && inflictor->cvmem
|
||||
&& inflictor->type != MT_BANANA) // Are there other designed trap items that can be deployed and dropped? If you add one, list it here!
|
||||
{
|
||||
type = DMG_STUMBLE;
|
||||
downgraded = true;
|
||||
player->ringburst += 5; // IT'S THE DAMAGE STUMBLE HACK AGAIN AAAAAAAAHHHHHHHHHHH
|
||||
K_PopPlayerShield(player);
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_SPHERES) && player->tripwireLeniency && !P_PlayerInPain(player))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DMG_EXPLODE:
|
||||
type = DMG_TUMBLE;
|
||||
downgraded = true;
|
||||
softenTumble = true;
|
||||
break;
|
||||
case DMG_TUMBLE:
|
||||
softenTumble = true;
|
||||
break;
|
||||
case DMG_NORMAL:
|
||||
case DMG_WIPEOUT:
|
||||
downgraded = true;
|
||||
type = DMG_STUMBLE;
|
||||
player->ringburst += 5; // THERE IS SIMPLY NO HOPE AT THIS POINT
|
||||
K_PopPlayerShield(player);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DMG_STING:
|
||||
K_DebtStingPlayer(player, source);
|
||||
K_KartPainEnergyFling(player);
|
||||
ringburst = 0;
|
||||
break;
|
||||
case DMG_STUMBLE:
|
||||
case DMG_WHUMBLE:
|
||||
K_StumblePlayer(player);
|
||||
ringburst = 5;
|
||||
break;
|
||||
case DMG_TUMBLE:
|
||||
K_TumblePlayer(player, inflictor, source, softenTumble);
|
||||
ringburst = 10;
|
||||
break;
|
||||
case DMG_EXPLODE:
|
||||
case DMG_KARMA:
|
||||
ringburst = K_ExplodePlayer(player, inflictor, source);
|
||||
break;
|
||||
case DMG_WIPEOUT:
|
||||
K_SpinPlayer(player, inflictor, source, KSPIN_WIPEOUT);
|
||||
K_KartPainEnergyFling(player);
|
||||
break;
|
||||
case DMG_VOLTAGE:
|
||||
case DMG_NORMAL:
|
||||
default:
|
||||
K_SpinPlayer(player, inflictor, source, KSPIN_SPINOUT);
|
||||
break;
|
||||
}
|
||||
|
||||
// Have a shield? You get hit, but don't lose your rings!
|
||||
if (player->curshield != KSHIELD_NONE)
|
||||
{
|
||||
ringburst = 0;
|
||||
}
|
||||
|
||||
player->ringburst += ringburst;
|
||||
|
||||
K_PopPlayerShield(player);
|
||||
|
||||
if ((type != DMG_STUMBLE && type != DMG_WHUMBLE) || (type == DMG_STUMBLE && downgraded))
|
||||
{
|
||||
if (type != DMG_STING)
|
||||
player->flashing = K_GetKartFlashing(player);
|
||||
player->instashield = 15;
|
||||
}
|
||||
|
||||
K_PlayPainSound(target, source);
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
player->spheres = min(player->spheres + 10, 40);
|
||||
|
||||
if ((hardhit == true && !softenTumble) || cv_kartdebughuddrop.value)
|
||||
{
|
||||
K_DropItems(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
K_DropHnextList(player);
|
||||
}
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->type == MT_BANANA)
|
||||
{
|
||||
player->flipDI = true;
|
||||
}
|
||||
|
||||
// Apply stun!
|
||||
if (type != DMG_STING)
|
||||
{
|
||||
K_ApplyStun(player, inflictor, source, damage, damagetype);
|
||||
}
|
||||
|
||||
K_DefensiveOverdrive(target->player);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target->type == MT_SPECIAL_UFO)
|
||||
{
|
||||
return Obj_SpecialUFODamage(target, inflictor, source, damagetype);
|
||||
}
|
||||
else if (target->type == MT_BLENDEYE_MAIN)
|
||||
{
|
||||
VS_BlendEye_Damage(target, inflictor, source, damage);
|
||||
}
|
||||
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Not a player, steal damage is intended to not do anything
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((target->flags & MF_BOSS) == MF_BOSS)
|
||||
{
|
||||
targetdamaging_t targetdamaging = UFOD_GENERIC;
|
||||
if (P_MobjWasRemoved(inflictor) == true)
|
||||
;
|
||||
else switch (inflictor->type)
|
||||
{
|
||||
case MT_GACHABOM:
|
||||
targetdamaging = UFOD_GACHABOM;
|
||||
break;
|
||||
case MT_ORBINAUT:
|
||||
case MT_ORBINAUT_SHIELD:
|
||||
targetdamaging = UFOD_ORBINAUT;
|
||||
break;
|
||||
case MT_BANANA:
|
||||
targetdamaging = UFOD_BANANA;
|
||||
break;
|
||||
case MT_INSTAWHIP:
|
||||
inflictor->extravalue2 = 1; // Disable whip collision
|
||||
targetdamaging = UFOD_WHIP;
|
||||
break;
|
||||
case MT_PLAYER:
|
||||
targetdamaging = UFOD_BOOST;
|
||||
break;
|
||||
case MT_JAWZ:
|
||||
case MT_JAWZ_SHIELD:
|
||||
targetdamaging = UFOD_JAWZ;
|
||||
break;
|
||||
case MT_SPB:
|
||||
targetdamaging = UFOD_SPB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
P_TrackRoundConditionTargetDamage(targetdamaging);
|
||||
}
|
||||
}
|
||||
|
||||
// do the damage
|
||||
if (damagetype & DMG_DEATHMASK)
|
||||
target->health = 0;
|
||||
else
|
||||
target->health -= damage;
|
||||
|
||||
if (source && source->player && target)
|
||||
G_GhostAddHit((INT32) (source->player - players), target);
|
||||
|
||||
// Insta-Whip (DMG_WHUMBLE): do not reduce hitlag because
|
||||
// this can leave room for double-damage.
|
||||
if ((damagetype & DMG_TYPEMASK) != DMG_WHUMBLE && (gametyperules & GTR_BUMPERS) && !battleprisons)
|
||||
laglength /= 2;
|
||||
|
||||
if (!(target->player && (damagetype & DMG_DEATHMASK)))
|
||||
K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||
|
||||
target->flags2 |= MF2_ALREADYHIT;
|
||||
|
||||
if (target->health <= 0)
|
||||
{
|
||||
P_KillMobj(target, inflictor, source, damagetype);
|
||||
return true;
|
||||
}
|
||||
|
||||
//K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||
|
||||
if (!player)
|
||||
{
|
||||
P_SetMobjState(target, target->info->painstate);
|
||||
|
||||
if (!P_MobjWasRemoved(target))
|
||||
{
|
||||
// if not intent on another player,
|
||||
// chase after this one
|
||||
P_SetTarget(&target->target, source);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Damages an object, which may or may not be a player.
|
||||
* For melee attacks, source and inflictor are the same.
|
||||
*
|
||||
|
|
@ -2874,6 +3673,9 @@ static boolean P_FlashingException(const player_t *player, const mobj_t *inflict
|
|||
*/
|
||||
boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
if (G_CompatLevel(0x0010))
|
||||
return P_DamageMobjCompat(target, inflictor, source, damage, damagetype);
|
||||
|
||||
player_t *player;
|
||||
player_t *playerInflictor;
|
||||
boolean force = false;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue