- scriptified A_Explode and relatives.

This commit is contained in:
Christoph Oelckers 2018-11-24 19:29:52 +01:00
parent 44d51a6de9
commit 652606f70b
8 changed files with 200 additions and 219 deletions

View file

@ -1186,119 +1186,6 @@ DEFINE_ACTION_FUNCTION(AActor, CheckInventory)
}
//==========================================================================
//
// Parameterized version of A_Explode
//
//==========================================================================
enum
{
XF_HURTSOURCE = 1,
XF_NOTMISSILE = 4,
XF_NOACTORTYPE = 1 << 3,
XF_NOSPLASH = 16,
};
DEFINE_ACTION_FUNCTION(AActor, A_Explode)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT (damage);
PARAM_INT (distance);
PARAM_INT (flags);
PARAM_BOOL (alert);
PARAM_INT (fulldmgdistance);
PARAM_INT (nails);
PARAM_INT (naildamage);
PARAM_CLASS (pufftype, AActor);
PARAM_NAME (damagetype);
if (damage < 0) // get parameters from metadata
{
damage = self->IntVar(NAME_ExplosionDamage);
distance = self->IntVar(NAME_ExplosionRadius);
flags = !self->BoolVar(NAME_DontHurtShooter);
alert = false;
}
if (distance <= 0) distance = damage;
// NailBomb effect, from SMMU but not from its source code: instead it was implemented and
// generalized from the documentation at http://www.doomworld.com/eternity/engine/codeptrs.html
if (nails)
{
DAngle ang;
for (int i = 0; i < nails; i++)
{
ang = i*360./nails;
// Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim
P_LineAttack(self, ang, MISSILERANGE, 0.,
//P_AimLineAttack (self, ang, MISSILERANGE),
naildamage, NAME_Hitscan, pufftype, (self->flags & MF_MISSILE) ? LAF_TARGETISSOURCE : 0);
}
}
if (!(flags & XF_NOACTORTYPE) && damagetype == NAME_None)
{
damagetype = self->DamageType;
}
int pflags = 0;
if (flags & XF_HURTSOURCE) pflags |= RADF_HURTSOURCE;
if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT;
int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, pflags, fulldmgdistance);
if (!(flags & XF_NOSPLASH)) P_CheckSplash(self, distance);
if (alert && self->target != NULL && self->target->player != NULL)
{
P_NoiseAlert(self->target, self);
}
ACTION_RETURN_INT(count);
}
//==========================================================================
//
// A_RadiusThrust
//
//==========================================================================
enum
{
RTF_AFFECTSOURCE = 1,
RTF_NOIMPACTDAMAGE = 2,
RTF_NOTMISSILE = 4,
};
DEFINE_ACTION_FUNCTION(AActor, A_RadiusThrust)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT (force);
PARAM_INT (distance);
PARAM_INT (flags);
PARAM_INT (fullthrustdistance);
bool sourcenothrust = false;
if (force == 0) force = 128;
if (distance <= 0) distance = abs(force);
// Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless.
if (!(flags & RTF_NOTMISSILE) && self->target != NULL && self->target->flags2 & MF2_NODMGTHRUST)
{
sourcenothrust = true;
self->target->flags2 &= ~MF2_NODMGTHRUST;
}
P_RadiusAttack (self, self->target, force, distance, self->DamageType, flags | RADF_NODAMAGE, fullthrustdistance);
P_CheckSplash(self, distance);
if (sourcenothrust)
{
self->target->flags2 |= MF2_NODMGTHRUST;
}
return 0;
}
//==========================================================================
//
// A_RadiusDamageSelf

View file

@ -3409,20 +3409,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain)
return 0;
}
//
// A_Detonate
// killough 8/9/98: same as A_Explode, except that the damage is variable
//
DEFINE_ACTION_FUNCTION(AActor, A_Detonate)
{
PARAM_SELF_PROLOGUE(AActor);
int damage = self->GetMissileDamage(0, 1);
P_RadiusAttack (self, self->target, damage, damage, self->DamageType, RADF_HURTSOURCE);
P_CheckSplash(self, damage);
return 0;
}
bool CheckBossDeath (AActor *actor)
{
int i;

View file

@ -359,7 +359,6 @@ void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff); // hitsc
void P_TraceBleed (int damage, AActor *target); // random direction version
bool P_HitFloor (AActor *thing);
bool P_HitWater (AActor *thing, sector_t *sec, const DVector3 &pos, bool checkabove = false, bool alert = true, bool force = false);
void P_CheckSplash(AActor *self, double distance);
struct FRailParams
{
@ -410,6 +409,7 @@ enum
RADF_SOURCEISSPOT = 4,
RADF_NODAMAGE = 8,
RADF_THRUSTZ = 16,
RADF_OLDRADIUSDAMAGE = 32
};
int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance,
FName damageType, int flags, int fulldamagedistance=0);

View file

@ -6229,7 +6229,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
// them far too "active." BossBrains also use the old code
// because some user levels require they have a height of 16,
// which can make them near impossible to hit with the new code.
if ((flags & RADF_NODAMAGE) || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG))
if (((flags & RADF_NODAMAGE) || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG)) && !(flags & RADF_OLDRADIUSDAMAGE))
{
double points = P_GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing);
double check = int(points) * bombdamage;
@ -6306,6 +6306,18 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
return count;
}
DEFINE_ACTION_FUNCTION(AActor, RadiusAttack)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(bombsource, AActor);
PARAM_INT(bombdamage);
PARAM_INT(bombdistance);
PARAM_NAME(damagetype);
PARAM_INT(flags);
PARAM_INT(fulldamagedistance);
ACTION_RETURN_INT(P_RadiusAttack(self, bombsource, bombdamage, bombdistance, damagetype, flags, fulldamagedistance));
}
//==========================================================================
//
// SECTOR HEIGHT CHANGING

View file

@ -6777,29 +6777,6 @@ DEFINE_ACTION_FUNCTION(AActor, HitFloor)
ACTION_RETURN_BOOL(P_HitFloor(self));
}
//---------------------------------------------------------------------------
//
// P_CheckSplash
//
// Checks for splashes caused by explosions
//
//---------------------------------------------------------------------------
void P_CheckSplash(AActor *self, double distance)
{
sector_t *floorsec;
self->Sector->LowestFloorAt(self, &floorsec);
if (self->Z() <= self->floorz + distance && self->floorsector == floorsec && self->Sector->GetHeightSec() == NULL && floorsec->heightsec == NULL)
{
// Explosion splashes never alert monsters. This is because A_Explode has
// a separate parameter for that so this would get in the way of proper
// behavior.
DVector3 pos = self->PosRelative(floorsec);
pos.Z = self->floorz;
P_HitWater (self, floorsec, pos, false, false);
}
}
//---------------------------------------------------------------------------
//
// FUNC P_CheckMissileSpawn

View file

@ -964,69 +964,6 @@ class Actor : Thinker native
native bool A_LineEffect(int boomspecial = 0, int tag = 0);
// End of MBF redundant functions.
//==========================================================================
//
// old customizable attack functions which use actor parameters.
//
//==========================================================================
private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
{
let targ = target;
if (targ == NULL) return;
A_FaceTarget ();
if (domelee && MeleeDamage>0 && CheckMeleeRange ())
{
int damage = random[CustomMelee](1, 8) * MeleeDamage;
if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
int newdam = targ.DamageMobj (self, self, damage, 'Melee');
targ.TraceBleed (newdam > 0 ? newdam : damage, self);
}
else if (domissile && MissileType != NULL)
{
// This seemingly senseless code is needed for proper aiming.
double add = MissileHeight + GetBobOffset() - 32;
AddZ(add);
Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), targ, MissileType, false);
AddZ(-add);
if (missile)
{
// automatic handling of seeker missiles
if (missile.bSeekerMissile)
{
missile.tracer = targ;
}
missile.CheckMissileSpawn(radius);
}
}
}
deprecated("2.3") void A_MeleeAttack()
{
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
}
deprecated("2.3") void A_MissileAttack()
{
Class<Actor> MissileType = MissileName;
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
}
deprecated("2.3") void A_ComboAttack()
{
Class<Actor> MissileType = MissileName;
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
}
void A_BasicAttack(int melee_damage, sound melee_sound, class<actor> missile_type, double missile_height)
{
DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height);
}
native void A_MonsterRail();
native void A_Pain();
native void A_NoBlocking(bool drop = true);
@ -1038,7 +975,6 @@ class Actor : Thinker native
native void A_VileChase();
native bool A_CheckForResurrection();
native void A_BossDeath();
native void A_Detonate();
bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0)
{
return Level.ExecuteSpecial(special, self, null, false, arg1, arg2, arg3, arg4, arg5);
@ -1110,10 +1046,10 @@ class Actor : Thinker native
native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true);
native void A_CustomComboAttack(class<Actor> missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true);
native void A_Burst(class<Actor> chunktype);
native void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0);
native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class<Actor> flashtype = null);
native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff", name damagetype = "none");
native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false);
native int RadiusAttack(Actor bombsource, int bombdamage, int bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, int fulldamagedistance = 0);
native void A_Stop();
native void A_Respawn(int flags = 1);
native void A_RestoreSpecialPosition();

View file

@ -529,7 +529,180 @@ extend class Actor
}
}
//---------------------------------------------------------------------------
//
// P_CheckSplash
//
// Checks for splashes caused by explosions
//
//---------------------------------------------------------------------------
void CheckSplash(double distance)
{
double floorh;
sector floorsec;
[floorh, floorsec] = curSector.LowestFloorAt(pos.XY);
if (pos.Z <= floorz + distance && floorsector == floorsec && curSector.GetHeightSec() == NULL && floorsec.heightsec == NULL)
{
// Explosion splashes never alert monsters. This is because A_Explode has
// a separate parameter for that so this would get in the way of proper
// behavior.
Vector3 pos = PosRelative(floorsec);
pos.Z = floorz;
HitWater (floorsec, pos, false, false);
}
}
//==========================================================================
//
// Parameterized version of A_Explode
//
//==========================================================================
int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldmgdistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff", name damagetype = "none")
{
if (damage < 0) // get parameters from metadata
{
damage = ExplosionDamage;
distance = ExplosionRadius;
flags = !DontHurtShooter;
alert = false;
}
if (distance <= 0) distance = damage;
// NailBomb effect, from SMMU but not from its source code: instead it was implemented and
// generalized from the documentation at http://www.doomworld.com/eternity/engine/codeptrs.html
if (nails)
{
double ang;
for (int i = 0; i < nails; i++)
{
ang = i*360./nails;
// Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim
LineAttack(ang, MISSILERANGE, 0.,
//P_AimLineAttack (self, ang, MISSILERANGE),
naildamage, 'Hitscan', pufftype, bMissile ? LAF_TARGETISSOURCE : 0);
}
}
if (!(flags & XF_EXPLICITDAMAGETYPE) && damagetype == 'None')
{
damagetype = self.DamageType;
}
int pflags = 0;
if (flags & XF_HURTSOURCE) pflags |= RADF_HURTSOURCE;
if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT;
int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldmgdistance);
if (!(flags & XF_NOSPLASH)) CheckSplash(distance);
if (alert && target != NULL && target.player != NULL)
{
SoundAlert(target);
}
return count;
}
//==========================================================================
//
// A_RadiusThrust
//
//==========================================================================
void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0)
{
if (force == 0) force = 128;
if (distance <= 0) distance = abs(force);
bool nothrust = target.bNoDamageThrust;
// Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless.
if (!(flags & RTF_NOTMISSILE) && target != NULL)
{
target.bNoDamageThrust = false;
}
RadiusAttack (target, force, distance, DamageType, flags | RADF_NODAMAGE, fullthrustdistance);
CheckSplash(distance);
target.bNoDamageThrust = nothrust;
}
//==========================================================================
//
// A_Detonate
// killough 8/9/98: same as A_Explode, except that the damage is variable
//
//==========================================================================
void A_Detonate()
{
int damage = GetMissileDamage(0, 1);
RadiusAttack (target, damage, damage, DamageType, RADF_HURTSOURCE);
CheckSplash(damage);
}
//==========================================================================
//
// old customizable attack functions which use actor parameters.
//
//==========================================================================
private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
{
let targ = target;
if (targ == NULL) return;
A_FaceTarget ();
if (domelee && MeleeDamage>0 && CheckMeleeRange ())
{
int damage = random[CustomMelee](1, 8) * MeleeDamage;
if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
int newdam = targ.DamageMobj (self, self, damage, 'Melee');
targ.TraceBleed (newdam > 0 ? newdam : damage, self);
}
else if (domissile && MissileType != NULL)
{
// This seemingly senseless code is needed for proper aiming.
double add = MissileHeight + GetBobOffset() - 32;
AddZ(add);
Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), targ, MissileType, false);
AddZ(-add);
if (missile)
{
// automatic handling of seeker missiles
if (missile.bSeekerMissile)
{
missile.tracer = targ;
}
missile.CheckMissileSpawn(radius);
}
}
}
deprecated("2.3") void A_MeleeAttack()
{
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
}
deprecated("2.3") void A_MissileAttack()
{
Class<Actor> MissileType = MissileName;
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
}
deprecated("2.3") void A_ComboAttack()
{
Class<Actor> MissileType = MissileName;
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
}
void A_BasicAttack(int melee_damage, sound melee_sound, class<actor> missile_type, double missile_height)
{
DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height);
}
}

View file

@ -1247,3 +1247,13 @@ enum SPAC
SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough|SPAC_UseBack),
};
enum RadiusDamageFlags
{
RADF_HURTSOURCE = 1,
RADF_NOIMPACTDAMAGE = 2,
RADF_SOURCEISSPOT = 4,
RADF_NODAMAGE = 8,
RADF_THRUSTZ = 16,
RADF_OLDRADIUSDAMAGE = 32
};