From 35ef7daf56ffd33aa3c482fad86bc1b4e49f81b0 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 21 Jan 2023 11:15:21 -0600 Subject: [PATCH] https://github.com/ZDoom/gzdoom/pull/1920 (A_Explode flags) --- src/playsim/p_local.h | 7 +- src/playsim/p_map.cpp | 88 +++++++++++++++---------- src/scripting/vmthunks_actors.cpp | 3 +- wadsrc/static/zscript/actors/actor.zs | 2 +- wadsrc/static/zscript/actors/attacks.zs | 3 + wadsrc/static/zscript/constants.zs | 9 ++- 6 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index e1fae8d62..750f05de1 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -406,9 +406,12 @@ enum RADF_SOURCEISSPOT = 4, RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, - RADF_OLDRADIUSDAMAGE = 32 + RADF_OLDRADIUSDAMAGE = 32, + RADF_THRUSTLESS = 64, + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; -int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg); +int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg, bool circular); int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, int flags, int fulldamagedistance=0, FName species = NAME_None); diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 589376fea..cf709d5e2 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -5838,7 +5838,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) //========================================================================== // // RADIUS ATTACK -// +// Most of the explosion code resides here. Except P_GeometryRadiusAttack(). // //========================================================================== @@ -5864,7 +5864,7 @@ CUSTOM_CVAR(Float, splashfactor, 1.f, CVAR_SERVERINFO) // Used by anything without OLDRADIUSDMG flag //========================================================================== -static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance, bool thingbombsource) +static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance, bool thingbombsource, bool round) { // [RH] New code. The bounding box only covers the // height of the thing and not the height of the map. @@ -5876,41 +5876,49 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance); double bombdamagefloat = (double)bombdamage; - DVector2 vec = bombspot->Vec2To(thing); - dx = fabs(vec.X); - dy = fabs(vec.Y); - boxradius = thing->radius; - - // The damage pattern is square, not circular. - len = double(dx > dy ? dx : dy); - - if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) + if (!round) { - double dz; + DVector2 vec = bombspot->Vec2To(thing); + dx = fabs(vec.X); + dy = fabs(vec.Y); + boxradius = thing->radius; - if (bombspot->Z() > thing->Z()) + // The damage pattern is square, not circular. + len = double(dx > dy ? dx : dy); + + if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) { - dz = double(bombspot->Z() - thing->Top()); - } - else - { - dz = double(thing->Z() - bombspot->Z()); - } - if (len <= boxradius) - { - len = dz; + double dz; + + if (bombspot->Z() > thing->Z()) + { + dz = double(bombspot->Z() - thing->Top()); + } + else + { + dz = double(thing->Z() - bombspot->Z()); + } + if (len <= boxradius) + { + len = dz; + } + else + { + len -= boxradius; + len = g_sqrt(len*len + dz*dz); + } } else { len -= boxradius; - len = g_sqrt(len*len + dz*dz); + if (len < 0.f) + len = 0.f; } } + //[inkoalwetrust]: Round explosions just use the actual distance between the source and victim. else { - len -= boxradius; - if (len < 0.f) - len = 0.f; + len = bombspot->Distance3D (thing); } len = clamp(len - (double)fulldamagedistance, 0, len); points = bombdamagefloat * (1. - len * bombdistancefloat); @@ -5985,7 +5993,7 @@ static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, // damage and not taking into account any damage reduction. //========================================================================== -int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg) +int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg, bool circular) { if (!thing) @@ -6005,7 +6013,7 @@ int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int const int newdam = oldradiusdmg ? GetOldRadiusDamage(true, self, thing, damage, distance, fulldmgdistance) - : int(GetRadiusDamage(true, self, thing, damage, distance, fulldmgdistance, false)); + : int(GetRadiusDamage(true, self, thing, damage, distance, fulldmgdistance, false, circular)); return newdam; } @@ -6072,10 +6080,12 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom ) ) continue; - if((species != NAME_None) && (thing->Species != species)) - { + if ((species != NAME_None) && (thing->Species != species)) + continue; + + //[inkoalawetrust] Don't harm actors friendly to the explosions' source. But do harm the source. + if ((flags & RADF_NOALLIES) && bombsource->IsFriend(thing) && !(thing == bombsource || thing == bombspot)) continue; - } if (bombsource && thing != bombsource && bombsource->player && P_ShouldPassThroughPlayer(bombsource, thing)) continue; @@ -6092,7 +6102,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if ((flags & RADF_NODAMAGE) || (!((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG) && !(flags & RADF_OLDRADIUSDAMAGE) && !(thing->Level->i_compatflags2 & COMPATF2_EXPLODE2))) { - double points = GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing); + double points = GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing,!!(flags & RADF_CIRCULAR)); double check = int(points) * bombdamage; // points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.) if ((check > 0 || (check == 0 && bombspot->flags7 & MF7_FORCEZERORADIUSDMG)) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) @@ -6101,15 +6111,22 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom double thrust; int damage = abs((int)points); int newdam = damage; + int dmgmask = 0; if (!(flags & RADF_NODAMAGE)) { + //[inkoalawetrust] Thrustless explosions don't push anything. + if (!(flags & RADF_THRUSTLESS)) + dmgmask = DMG_EXPLOSION; + else + dmgmask = DMG_EXPLOSION | DMG_THRUSTLESS; + //[MC] Don't count actors saved by buddha if already at 1 health. int prehealth = thing->health; - newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod, DMG_EXPLOSION); + newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod, dmgmask); if (thing->health < prehealth) count++; } - else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE) && !(thing->flags7 & MF7_DONTTHRUST))) + else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE && !(flags & RADF_THRUSTLESS)) && !(thing->flags7 & MF7_DONTTHRUST))) thing->flags2 |= MF2_BLASTED; if (!(thing->flags & MF_ICECORPSE)) @@ -6117,13 +6134,12 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if (!(flags & RADF_NODAMAGE) && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed(newdam > 0 ? newdam : damage, thing, bombspot); - if ((flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST)) + if ((flags & RADF_NODAMAGE && !(flags & RADF_THRUSTLESS)) || !(bombspot->flags2 & MF2_NODMGTHRUST) && !(flags & RADF_THRUSTLESS)) { if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) { if (!(thing->flags7 & MF7_DONTTHRUST)) { - thrust = points * 0.5 / (double)thing->Mass; if (bombsource == thing) { diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 244a05879..c9c459557 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1302,7 +1302,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetRadiusDamage, P_GetRadiusDamage) PARAM_INT(distance); PARAM_INT(fulldmgdistance); PARAM_BOOL(oldradiusdmg); - ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg)); + PARAM_BOOL(circular); + ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg, circular)); } static int RadiusAttack(AActor *self, AActor *bombsource, int bombdamage, int bombdistance, int damagetype, int flags, int fulldamagedistance, int species) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 9a007dd49..30c763463 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1187,7 +1187,7 @@ class Actor : Thinker native native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); native void A_Burst(class chunktype); native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class flashtype = null); - native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false); + native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false, bool circular = false); native int RadiusAttack(Actor bombsource, int bombdamage, int bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, int fulldamagedistance = 0, name species = "None"); native void A_Respawn(int flags = 1); diff --git a/wadsrc/static/zscript/actors/attacks.zs b/wadsrc/static/zscript/actors/attacks.zs index edefdd24f..ac754d1e1 100644 --- a/wadsrc/static/zscript/actors/attacks.zs +++ b/wadsrc/static/zscript/actors/attacks.zs @@ -606,6 +606,9 @@ extend class Actor if (flags & XF_HURTSOURCE) pflags |= RADF_HURTSOURCE; if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT; if (flags & XF_THRUSTZ) pflags |= RADF_THRUSTZ; + if (flags & XF_THRUSTLESS) pflags |= RADF_THRUSTLESS; + if (flags & XF_NOALLIES) pflags |= RADF_NOALLIES; + if (flags & XF_CIRCULAR) pflags |= RADF_CIRCULAR; int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldamagedistance); if (!(flags & XF_NOSPLASH)) CheckSplash(distance); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 66426a125..bb2c8bd10 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -261,7 +261,9 @@ enum EExplodeFlags XF_EXPLICITDAMAGETYPE = 8, XF_NOSPLASH = 16, XF_THRUSTZ = 32, - + XF_THRUSTLESS = 64, + XF_NOALLIES = 128, + XF_CIRCULAR = 256, }; // Flags for A_RadiusThrust @@ -1227,7 +1229,10 @@ enum RadiusDamageFlags RADF_SOURCEISSPOT = 4, RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, - RADF_OLDRADIUSDAMAGE = 32 + RADF_OLDRADIUSDAMAGE = 32, + RADF_THRUSTLESS = 64, + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; enum IntermissionSequenceType