From 194f73a94bb7e410d1bdb0fdb05d20997ffaa1c7 Mon Sep 17 00:00:00 2001 From: inkoalawetrust <56005600+inkoalawetrust@users.noreply.github.com> Date: Sat, 7 Jan 2023 07:07:14 +0200 Subject: [PATCH] Added (XF/RADF)_CIRCULAR. This flag makes explosions use a spherical radius, instead of a cubic one. Only took almost 30 years. --- src/playsim/p_local.h | 5 +- src/playsim/p_map.cpp | 70 ++++++++++++++----------- src/scripting/vmthunks_actors.cpp | 3 +- wadsrc/static/zscript/actors/actor.zs | 2 +- wadsrc/static/zscript/actors/attacks.zs | 1 + wadsrc/static/zscript/constants.zs | 4 +- 6 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index 104ca97c3..750f05de1 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -408,9 +408,10 @@ enum RADF_THRUSTZ = 16, RADF_OLDRADIUSDAMAGE = 32, RADF_THRUSTLESS = 64, - RADF_NOALLIES = 128 + 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 32dd718d1..32b145eb1 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; } @@ -6075,8 +6083,8 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if ((species != NAME_None) && (thing->Species != species)) continue; - //[inkoalawetrust] Don't harm actors friendly to the explosions' source. - if ((flags & RADF_NOALLIES) && bombsource->IsFriend(thing)) + //[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)) @@ -6094,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)) diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index f302d335d..05e482c2c 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 0baa6acb0..ac754d1e1 100644 --- a/wadsrc/static/zscript/actors/attacks.zs +++ b/wadsrc/static/zscript/actors/attacks.zs @@ -608,6 +608,7 @@ extend class Actor 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 d2690c817..75ad1ac62 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -263,6 +263,7 @@ enum EExplodeFlags XF_THRUSTZ = 32, XF_THRUSTLESS = 64, XF_NOALLIES = 128, + XF_CIRCULAR = 256, }; // Flags for A_RadiusThrust @@ -1230,7 +1231,8 @@ enum RadiusDamageFlags RADF_THRUSTZ = 16, RADF_OLDRADIUSDAMAGE = 32, RADF_THRUSTLESS = 64, - RADF_NOALLIES = 128 + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; enum IntermissionSequenceType