- scriptified ArtiBlastRadius.

This commit is contained in:
Christoph Oelckers 2016-11-26 09:51:14 +01:00
parent 7385cd70c0
commit 4e802652c7
12 changed files with 273 additions and 175 deletions

View file

@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES
${OTHER_SYSTEM_SOURCES}
sc_man_scanner.h
sc_man_scanner.re
g_hexen/a_blastradius.cpp
g_hexen/a_boostarmor.cpp
g_hexen/a_clericflame.cpp
g_hexen/a_clericholy.cpp

View file

@ -1,158 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
*/
/* For reference, the default values:
#define BLAST_RADIUS_DIST 255*F.RACUNIT
#define BLAST_SPEED 20*F.RACUNIT
#define BLAST_FULLSTRENGTH 255
*/
// Disc of Repulsion --------------------------------------------------------
//==========================================================================
//
// AArtiBlastRadius :: BlastActor
//
//==========================================================================
void BlastActor (AActor *victim, double strength, double speed, AActor *Owner, PClassActor *blasteffect, bool dontdamage)
{
DAngle angle;
AActor *mo;
DVector3 pos;
if (!victim->SpecialBlastHandling (Owner, strength))
{
return;
}
angle = Owner->AngleTo(victim);
DVector2 move = angle.ToVector(speed);
victim->Vel.X = move.X;
victim->Vel.Y = move.Y;
// Spawn blast puff
angle -= 180.;
pos = victim->Vec3Offset(
(victim->radius + 1) * angle.Cos(),
(victim->radius + 1) * angle.Sin(),
(victim->Height / 2) - victim->Floorclip);
mo = Spawn (blasteffect, pos, ALLOW_REPLACE);
if (mo)
{
mo->Vel.X = victim->Vel.X;
mo->Vel.Y = victim->Vel.Y;
}
if (victim->flags & MF_MISSILE)
{
// [RH] Floor and ceiling huggers should not be blasted vertically.
if (!(victim->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
mo->Vel.Z = victim->Vel.Z = 8;
}
}
else
{
victim->Vel.Z = 1000. / victim->Mass;
}
if (victim->player)
{
// Players handled automatically
}
else if (!dontdamage)
{
victim->flags2 |= MF2_BLASTED;
}
if (victim->flags6 & MF6_TOUCHY)
{ // Touchy objects die when blasted
victim->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj(victim, Owner, Owner, victim->health, NAME_Melee, DMG_FORCED);
}
}
enum
{
BF_USEAMMO = 1,
BF_DONTWARN = 2,
BF_AFFECTBOSSES = 4,
BF_NOIMPACTDAMAGE = 8,
};
//==========================================================================
//
// AArtiBlastRadius :: Activate
//
// Blast all actors away
//
//==========================================================================
DEFINE_ACTION_FUNCTION (AActor, A_Blast)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_INT_DEF (blastflags)
PARAM_FLOAT_DEF (strength)
PARAM_FLOAT_DEF (radius)
PARAM_FLOAT_DEF (speed)
PARAM_CLASS_DEF (blasteffect, AActor)
PARAM_SOUND_DEF (blastsound)
AActor *mo;
TThinkerIterator<AActor> iterator;
if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_PSPRITE())
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && !weapon->DepleteAmmo(weapon->bAltFire))
{
return 0;
}
}
S_Sound (self, CHAN_AUTO, blastsound, 1, ATTN_NORM);
if (!(blastflags & BF_DONTWARN))
{
P_NoiseAlert (self, self);
}
while ( (mo = iterator.Next ()) )
{
if ((mo == self) || ((mo->flags2 & MF2_BOSS) && !(blastflags & BF_AFFECTBOSSES))
|| (mo->flags2 & MF2_DORMANT) || (mo->flags3 & MF3_DONTBLAST))
{ // Not a valid monster: originator, boss, dormant, or otherwise protected
continue;
}
if ((mo->flags & MF_ICECORPSE) || (mo->flags3 & MF3_CANBLAST))
{
// Let these special cases go
}
else if ((mo->flags3 & MF3_ISMONSTER) && (mo->health <= 0))
{
continue;
}
else if (!(mo->player) &&
!(mo->flags & MF_MISSILE) &&
!(mo->flags3 & (MF3_ISMONSTER|MF3_CANBLAST)) &&
!(mo->flags6 & (MF6_TOUCHY|MF6_VULNERABLE)))
{ // Must be monster, player, missile, touchy or vulnerable
continue;
}
if (self->Distance2D(mo) > radius)
{ // Out of range
continue;
}
if (mo->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, mo))
{
// in another region and cannot be seen.
continue;
}
BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE));
}
return 0;
}

View file

@ -24,7 +24,6 @@
#include "serializer.h"
// Include all the Hexen stuff here to reduce compile time
#include "a_blastradius.cpp"
#include "a_boostarmor.cpp"
#include "a_clericflame.cpp"
#include "a_clericholy.cpp"

View file

@ -262,7 +262,15 @@ void P_NoiseAlert (AActor *target, AActor *emitter, bool splash, double maxdist)
}
}
DEFINE_ACTION_FUNCTION(AActor, NoiseAlert)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(emitter, AActor);
PARAM_BOOL_DEF(splash);
PARAM_FLOAT_DEF(maxdist);
P_NoiseAlert(self, emitter, splash, maxdist);
return 0;
}
//----------------------------------------------------------------------------

View file

@ -22,7 +22,6 @@
//-----------------------------------------------------------------------------
// HEADER FILES ------------------------------------------------------------
#include <float.h>
#include "templates.h"
#include "i_system.h"
@ -3342,6 +3341,16 @@ bool AActor::SpecialBlastHandling (AActor *source, double strength)
return true;
}
// This only gets called from the script side so we do not need a native wrapper like for the other virtual methods.
DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(source, AActor);
PARAM_FLOAT(strength);
ACTION_RETURN_BOOL(self->SpecialBlastHandling(source, strength));
}
int AActor::SpecialMissileHit (AActor *victim)
{
return -1;

View file

@ -1265,3 +1265,48 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake
}
return baselight;
}
DEFINE_FIELD_X(Sector, sector_t, floorplane)
DEFINE_FIELD_X(Sector, sector_t, ceilingplane)
DEFINE_FIELD_X(Sector, sector_t, ColorMap)
DEFINE_FIELD_X(Sector, sector_t, SoundTarget)
DEFINE_FIELD_X(Sector, sector_t, special)
DEFINE_FIELD_X(Sector, sector_t, lightlevel)
DEFINE_FIELD_X(Sector, sector_t, seqType)
DEFINE_FIELD_X(Sector, sector_t, sky)
DEFINE_FIELD_X(Sector, sector_t, SeqName)
DEFINE_FIELD_X(Sector, sector_t, centerspot)
DEFINE_FIELD_X(Sector, sector_t, validcount)
DEFINE_FIELD_X(Sector, sector_t, thinglist)
DEFINE_FIELD_X(Sector, sector_t, friction)
DEFINE_FIELD_X(Sector, sector_t, movefactor)
DEFINE_FIELD_X(Sector, sector_t, terrainnum)
DEFINE_FIELD_X(Sector, sector_t, floordata)
DEFINE_FIELD_X(Sector, sector_t, ceilingdata)
DEFINE_FIELD_X(Sector, sector_t, lightingdata)
DEFINE_FIELD_X(Sector, sector_t, interpolations)
DEFINE_FIELD_X(Sector, sector_t, soundtraversed)
DEFINE_FIELD_X(Sector, sector_t, stairlock)
DEFINE_FIELD_X(Sector, sector_t, prevsec)
DEFINE_FIELD_X(Sector, sector_t, nextsec)
DEFINE_FIELD_X(Sector, sector_t, linecount)
DEFINE_FIELD_X(Sector, sector_t, lines)
DEFINE_FIELD_X(Sector, sector_t, heightsec)
DEFINE_FIELD_X(Sector, sector_t, bottommap)
DEFINE_FIELD_X(Sector, sector_t, midmap)
DEFINE_FIELD_X(Sector, sector_t, topmap)
DEFINE_FIELD_X(Sector, sector_t, touching_thinglist)
DEFINE_FIELD_X(Sector, sector_t, render_thinglist)
DEFINE_FIELD_X(Sector, sector_t, gravity)
DEFINE_FIELD_X(Sector, sector_t, damagetype)
DEFINE_FIELD_X(Sector, sector_t, damageamount)
DEFINE_FIELD_X(Sector, sector_t, damageinterval)
DEFINE_FIELD_X(Sector, sector_t, leakydamage)
DEFINE_FIELD_X(Sector, sector_t, ZoneNumber)
DEFINE_FIELD_X(Sector, sector_t, MoreFlags)
DEFINE_FIELD_X(Sector, sector_t, Flags)
DEFINE_FIELD_X(Sector, sector_t, SecActTarget)
DEFINE_FIELD_X(Sector, sector_t, Portals)
DEFINE_FIELD_X(Sector, sector_t, PortalGroup)
DEFINE_FIELD_X(Sector, sector_t, sectornum)

View file

@ -983,8 +983,8 @@ public:
BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
// jff 2/26/98 lockout machinery for stairbuilding
SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally
SWORD prevsec; // -1 or number of sector for previous step
SWORD nextsec; // -1 or number of next step sector
int prevsec; // -1 or number of sector for previous step
int nextsec; // -1 or number of next step sector
short linecount;
struct line_t **lines; // [linecount] size

View file

@ -265,6 +265,7 @@ class Actor : Thinker native
virtual native void Die(Actor source, Actor inflictor, int dmgflags);
virtual native bool Slam(Actor victim);
virtual native bool UseInventory(Inventory item);
virtual native bool SpecialBlastHandling (Actor source, double strength);
native void AdjustPlayerAngle(FTranslatedLineTarget t);
@ -279,6 +280,7 @@ class Actor : Thinker native
native bool isTeammate(Actor other);
native int PlayerNumber();
native void SetFriendPlayer(PlayerInfo player);
native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0);
native void RestoreDamage();
native int SpawnHealth();
@ -669,7 +671,6 @@ 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);
action native void A_Blast(int flags = 0, double strength = 255, double radius = 255, double speed = 20, class<Actor> blasteffect = "BlastEffect", sound blastsound = "BlastRadius");
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");

View file

@ -131,6 +131,72 @@ struct F3DFloor native
struct Sector native
{
//secplane_t floorplane, ceilingplane;
//FDynamicColormap *ColorMap; // [RH] Per-sector colormap
native Actor SoundTarget;
native int16 special;
native int16 lightlevel;
native int16 seqType;
native int sky;
native Name SeqName;
native readonly Vector2 centerspot;
native int validcount;
//AActor* thinglist;
native double friction, movefactor;
native int terrainnum[2];
// thinker_t for reversable actions
//SectorEffect floordata;
//SectorEffect ceilingdata;
//SectorEffect lightingdata;
enum EInterpolationType
{
CeilingMove,
FloorMove,
CeilingScroll,
FloorScroll
};
//Interpolation interpolations[4];
native uint8 soundtraversed;
native int8 stairlock;
native int prevsec;
native int nextsec;
native readonly int16 linecount;
//line_t **lines;
native readonly Sector heightsec;
native uint bottommap, midmap, topmap;
//struct msecnode_t *touching_thinglist;
//struct msecnode_t *render_thinglist;
native double gravity;
native Name damagetype;
native int damageamount;
native int16 damageinterval;
native int16 leakydamage;
native uint16 ZoneNumber;
native uint16 MoreFlags;
native uint Flags;
native SectorAction SecActTarget;
native readonly uint Portals[2];
native readonly int PortalGroup;
native readonly int sectornum;
native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0);
}

View file

@ -1,4 +1,12 @@
class HereticWeapon : Weapon
{
Default
{
Weapon.Kickback 150;
}
}
// Pod ----------------------------------------------------------------------
class Pod : Actor

View file

@ -1,13 +1,3 @@
class HereticWeapon : Weapon
{
Default
{
Weapon.Kickback 150;
}
}
// Phoenix Rod --------------------------------------------------------------
class PhoenixRod : Weapon

View file

@ -20,6 +20,137 @@ class ArtiBlastRadius : CustomInventory
Use:
TNT1 A 0 A_Blast;
}
}
//==========================================================================
//
// A_Blast is public to Actor
//
//==========================================================================
extend class Actor
{
/* For reference, the default values:
#define BLAST_RADIUS_DIST 255.0
#define BLAST_SPEED 20.0
#define BLAST_FULLSTRENGTH 255
*/
//==========================================================================
//
// AArtiBlastRadius :: BlastActor
//
//==========================================================================
private void BlastActor (Actor victim, double strength, double speed, Class<Actor> blasteffect, bool dontdamage)
{
if (!victim.SpecialBlastHandling (self, strength))
{
return;
}
double ang = AngleTo(victim);
Vector2 move = AngleToVector(ang, speed);
victim.Vel.XY = move;
// Spawn blast puff
ang -= 180.;
Vector3 spawnpos = victim.Vec3Offset(
(victim.radius + 1) * cos(ang),
(victim.radius + 1) * sin(ang),
(victim.Height / 2) - victim.Floorclip);
Actor mo = Spawn (blasteffect, spawnpos, ALLOW_REPLACE);
if (mo)
{
mo.Vel.XY = victim.Vel.XY;
}
if (victim.bMissile)
{
// [RH] Floor and ceiling huggers should not be blasted vertically.
if (!victim.bFloorHugger && !victim.bCeilingHugger)
{
mo.Vel.Z = victim.Vel.Z = 8;
}
}
else
{
victim.Vel.Z = 1000. / victim.Mass;
}
if (victim.player)
{
// Players handled automatically
}
else if (!dontdamage)
{
victim.bBlasted = true;
}
if (victim.bTouchy)
{ // Touchy objects die when blasted
victim.bArmed = false; // Disarm
victim.DamageMobj(self, self, victim.health, 'Melee', DMG_FORCED);
}
}
//==========================================================================
//
// AArtiBlastRadius :: Activate
//
// Blast all actors away
//
//==========================================================================
action void A_Blast(int blastflags = 0, double strength = 255, double radius = 255, double speed = 20, class<Actor> blasteffect = "BlastEffect", sound blastsound = "BlastRadius")
{
Weapon weapon = player.ReadyWeapon;
if (player && (blastflags & BF_USEAMMO) && invoker == weapon && stateinfo != null && stateinfo.mStateType == STATE_Psprite)
{
if (weapon != null && !weapon.DepleteAmmo(weapon.bAltFire))
{
return;
}
}
A_PlaySound (blastsound, CHAN_AUTO);
if (!(blastflags & BF_DONTWARN))
{
NoiseAlert (self);
}
ThinkerIterator it = ThinkerIterator.Create("Actor");
Actor mo;
while ( (mo = Actor(it.Next ())) )
{
if (mo == self || (mo.bBoss && !(blastflags & BF_AFFECTBOSSES)) || mo.bDormant || mo.bDontBlast)
{ // Not a valid monster: originator, boss, dormant, or otherwise protected
continue;
}
if (mo.bIceCorpse || mo.bCanBlast)
{
// Let these special cases go
}
else if (mo.bIsMonster && mo.health <= 0)
{
continue;
}
else if (!mo.player && !mo.bMissile && !mo.bIsMonster && !mo.bCanBlast && !mo.bTouchy && !mo.bVulnerable)
{ // Must be monster, player, missile, touchy or vulnerable
continue;
}
if (Distance2D(mo) > radius)
{ // Out of range
continue;
}
if (mo.CurSector.PortalGroup != CurSector.PortalGroup && !CheckSight(mo))
{
// in another region and cannot be seen.
continue;
}
BlastActor (mo, strength, speed, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE));
}
}
}
// Blast Effect -------------------------------------------------------------