Omnisight now handles 3d floors and midtextures, and exit line merging works properly. Reduced Pusher primary fire damage slightly. Cleared improper usages of GetAge().
539 lines
12 KiB
Text
539 lines
12 KiB
Text
// Gore FX ported over from Soundless Mound, with some edits
|
|
|
|
// Base blood actor
|
|
Class mkBlood : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+PUFFGETSOWNER;
|
|
}
|
|
action void A_Bleed( int str = 1 )
|
|
{
|
|
if ( !target ) return;
|
|
let b = Spawn("mkBloodSpray",pos);
|
|
Vector2 dirto = target.Vec2To(self).unit();
|
|
b.angle = atan2(dirto.y,dirto.x);
|
|
b.pitch = FRandom[Blood](-60,30);
|
|
b.translation = translation;
|
|
b.target = target;
|
|
b.args[0] = str;
|
|
if ( target.bloodcolor ) b.SetShade(Color(target.bloodcolor.r/2,target.bloodcolor.g/2,target.bloodcolor.b/2));
|
|
else b.SetShade(Color(80,0,0));
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1 NoDelay A_Bleed(3);
|
|
Stop;
|
|
TNT1 A 1 A_Bleed(2);
|
|
Stop;
|
|
TNT1 A 1 A_Bleed(1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// a burst of blood attached to a bleeding actor
|
|
Class mkBloodSpray : Actor
|
|
{
|
|
double str;
|
|
int cnt;
|
|
Vector3 attachofs;
|
|
double baseang;
|
|
color shadecol;
|
|
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
str = FRandom[Blood](2.,4.)*args[0];
|
|
cnt = Random[Blood](2,3)*args[0];
|
|
attachofs.xy = RotateVector(target.Vec2To(self),-target.angle);
|
|
attachofs.z = pos.z-target.pos.z;
|
|
baseang = angle-target.angle;
|
|
}
|
|
private bool IsTargetFlying()
|
|
{
|
|
if ( !target ) return false;
|
|
if ( !target.bNOGRAVITY && (target.pos.z > target.floorz) && target.TestMobjZ() ) return true;
|
|
if ( ((!target.bNOGRAVITY && target.bBlasted) || (target.health <= 0)) && (target.vel.length() > 10.) ) return true;
|
|
return false;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( isFrozen() ) return;
|
|
Vector3 setofs;
|
|
setofs = (cos(target.angle)*attachofs.x+sin(target.angle)*attachofs.y,sin(target.angle)*attachofs.x-cos(target.angle)*attachofs.y,attachofs.z);
|
|
SetOrigin(level.Vec3Offset(target.pos,setofs),false);
|
|
int sz = args[0];
|
|
double ang, pt;
|
|
for ( int i=0; i<max(1,sz/2); i++ )
|
|
{
|
|
let d = Spawn("mkBloodDrop",pos);
|
|
d.SetShade(fillcolor);
|
|
ang = baseang+target.angle+FRandom[Blood](-15.,15.)*str;
|
|
pt = pitch+FRandom[Blood](-15.,15.)*str;
|
|
Vector3 dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt));
|
|
d.vel = dir*str*FRandom[Blood](.8,1.8);
|
|
d.scale *= str*.15*FRandom[Blood](.6,1.4);
|
|
}
|
|
bool flying = IsTargetFlying();
|
|
if ( !flying ) str *= 1.-(.4/sz);
|
|
if ( (str <= .05) || ((cnt-- <= 0) && !flying) ) Destroy();
|
|
}
|
|
}
|
|
|
|
// drop of salsa
|
|
// becomes a flatsprite on crash
|
|
Class mkBloodDrop : Actor
|
|
{
|
|
int deadtimer;
|
|
bool dead;
|
|
|
|
Default
|
|
{
|
|
+MISSILE;
|
|
+DROPOFF;
|
|
+NOTELEPORT;
|
|
+THRUACTORS;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
Scale .35;
|
|
Radius 2;
|
|
Height 2;
|
|
Mass 1;
|
|
RenderStyle "Shaded";
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( waterlevel > 0 ) A_FadeOut();
|
|
if ( dead )
|
|
{
|
|
deadtimer++;
|
|
if ( deadtimer > 350 ) A_FadeOut(.01);
|
|
return;
|
|
}
|
|
scale *= .99;
|
|
if ( scale.x <= 0. ) Destroy();
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
deadtimer = Random[Blood](-20,20);
|
|
int jumps = Random[Blood](0,3);
|
|
state dest = ResolveState("Spawn");
|
|
SetState(dest+jumps);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SBLD ABCD 2;
|
|
Loop;
|
|
Death:
|
|
SBLD E 0
|
|
{
|
|
invoker.dead = true;
|
|
A_StartSound("misc/blooddrop",volume:.1);
|
|
if ( pos.z > floorz )
|
|
{
|
|
// TODO trace decal
|
|
return ResolveState("Null");
|
|
}
|
|
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360));
|
|
return ResolveState(null);
|
|
}
|
|
SBLD # -1
|
|
{
|
|
A_Stop();
|
|
frame = Random[Blood](5,8);
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// chunky salsa in the air
|
|
Class mkBloodSmoke : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOINTERACTION;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
Scale .5;
|
|
Alpha .35;
|
|
RenderStyle "Shaded";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
int jumps = Random[Blood](0,19);
|
|
state dest = ResolveState("Spawn");
|
|
SetState(dest+jumps);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
UpdateWaterLevel();
|
|
if ( waterlevel > 0 ) A_FadeOut();
|
|
A_FadeOut(.03);
|
|
A_SetScale(scale.x*1.02);
|
|
if ( tics > 0 ) tics--;
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
tics = CurState.tics;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BSMK ABCDEFGHIJKLMNOPQRST 2;
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
Class mkBloodSmoke2 : mkBloodSmoke
|
|
{
|
|
Default
|
|
{
|
|
Scale .8;
|
|
Alpha 1.;
|
|
}
|
|
}
|
|
|
|
// flying gibs
|
|
// inspired by Lud's Universal Gibs
|
|
Class mkFlyingGib : Actor
|
|
{
|
|
int deadtimer;
|
|
int lastbleed;
|
|
color shadecol;
|
|
bool bleeding;
|
|
double rollvel;
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
frame = Random[Blood](0,5);
|
|
double ang = FRandom[Gibs](0,360);
|
|
double pt = FRandom[Gibs](-60,20);
|
|
Vector3 dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
|
|
vel += dir*FRandom[Gibs](5.,20.);
|
|
if ( master ) vel += master.vel*1.5;
|
|
deadtimer = Random[Gibs](-20,20);
|
|
rollvel = FRandom[Gibs](10,50)*RandomPick[Gibs](-1,1);
|
|
scale *= FRandom[Gibs](.5,1.5);
|
|
if ( master && master.bloodcolor ) shadecol = Color(master.bloodcolor.r/2,master.bloodcolor.g/2,master.bloodcolor.b/2);
|
|
else shadecol = Color(80,0,0);
|
|
bleeding = true;
|
|
if ( Random[Blood](0,1) ) bXFlip = true;
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( isFrozen() ) return;
|
|
if ( bleeding && !Random[Blood](0,3) )
|
|
{
|
|
let s = Spawn("mkBloodSmoke",pos);
|
|
s.SetShade(shadecol);
|
|
}
|
|
if ( CurState == ResolveState("Death2") )
|
|
{
|
|
if ( vel.length() < .1 ) bleeding = false;
|
|
deadtimer++;
|
|
if ( deadtimer > 300 ) A_FadeOut(.01);
|
|
return;
|
|
}
|
|
roll += rollvel;
|
|
}
|
|
|
|
override bool CanCollideWith(Actor other, bool passive)
|
|
{
|
|
if ( other == master ) return false;
|
|
return true;
|
|
}
|
|
|
|
action void A_Bleed()
|
|
{
|
|
double ang;
|
|
double pt;
|
|
Vector3 dir;
|
|
if ( level.maptime <= invoker.lastbleed ) return;
|
|
invoker.lastbleed = level.maptime;
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
let b = Spawn("mkBloodDrop",pos);
|
|
ang = FRandom[Gibs](0,360);
|
|
pt = FRandom[Gibs](-60,30);
|
|
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
|
|
b.vel = dir*FRandom[Gibs](0.3,2.2)*vel.length();
|
|
b.scale *= 2.0;
|
|
b.SetShade(invoker.shadecol);
|
|
}
|
|
}
|
|
|
|
Default
|
|
{
|
|
Radius 4;
|
|
Height 4;
|
|
Mass 10;
|
|
Scale .65;
|
|
Gravity .5;
|
|
BounceType "Doom";
|
|
BounceFactor .6;
|
|
+MISSILE;
|
|
+DROPOFF;
|
|
+NOBLOCKMAP;
|
|
+USEBOUNCESTATE;
|
|
+BOUNCEONCEILINGS;
|
|
+MOVEWITHSECTOR;
|
|
+THRUACTORS;
|
|
+NOTELEPORT;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+INTERPOLATEANGLES;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SGIB # 1;
|
|
Wait;
|
|
Bounce:
|
|
SGIB # 0
|
|
{
|
|
A_Bleed();
|
|
A_StartSound("misc/gibhit",CHAN_BODY,CHANF_OVERLAP);
|
|
}
|
|
Goto Spawn;
|
|
Death:
|
|
SGIB # 1 A_JumpIf(pos.z<=floorz,"Death2");
|
|
Wait;
|
|
Death2:
|
|
SGIB # -1
|
|
{
|
|
A_StartSound("misc/gibhit",CHAN_BODY,CHANF_OVERLAP);
|
|
roll = RandomPick[Gibs](0,180)+Random[Gibs](-5,5);
|
|
A_Stop();
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// Manually added gibbing
|
|
Class mkGibber : Actor
|
|
{
|
|
Actor Gibbed;
|
|
int gibcount, gibsize;
|
|
int delay;
|
|
color shadecol;
|
|
|
|
virtual void BurstGibs()
|
|
{
|
|
Actor a;
|
|
double ang, pt;
|
|
Vector3 dir;
|
|
bool dummy;
|
|
for ( int i=0; i<gibsize; i++ )
|
|
{
|
|
a = Spawn("mkBloodSmoke2",pos+(FRandom[Gibs](-.8,.8)*radius,FRandom[Gibs](-.8,.8)*radius,FRandom[Gibs](0.,.9)*height));
|
|
a.SetShade(shadecol);
|
|
}
|
|
for ( int i=0; i<2*gibsize; i++ )
|
|
{
|
|
[dummy, a] = A_SpawnItemEx("mkFlyingGib",FRandom[Gibs](-.5,.5)*radius,FRandom[Gibs](-.5,.5)*radius,FRandom[Gibs](.1,.9)*height,flags:SXF_ABSOLUTEANGLE|SXF_USEBLOODCOLOR);
|
|
a.translation = translation;
|
|
a.scale *= scale.x;
|
|
a.master = gibbed;
|
|
}
|
|
for ( int i=0; i<3*gibsize; i++ )
|
|
{
|
|
[dummy, a] = A_SpawnItemEx("mkBloodDrop",FRandom[Gibs](-.8,.8)*radius,FRandom[Gibs](-.8,.8)*radius,FRandom[Gibs](0.,.9)*height,flags:SXF_ABSOLUTEANGLE|SXF_USEBLOODCOLOR);
|
|
ang = FRandom[Gibs](0,360);
|
|
pt = FRandom[Gibs](-90,90);
|
|
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
|
|
a.vel = dir*FRandom[Gibs](8.,24.);
|
|
a.scale *= 2.+FRandom[Gibs](.3,1.6);
|
|
a.SetShade(shadecol);
|
|
}
|
|
reactiontime--;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
gibsize = int(min(max(radius,height)/15,6));
|
|
reactiontime = int(min(max(radius,height)/10,8));
|
|
if ( gibbed && gibbed.bloodcolor ) shadecol = Color(gibbed.bloodcolor.r/2,gibbed.bloodcolor.g/2,gibbed.bloodcolor.b/2);
|
|
else shadecol = Color(80,0,0);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !gibbed )
|
|
{
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
return;
|
|
}
|
|
SetOrigin(gibbed.pos,true);
|
|
scale = gibbed.scale;
|
|
vel = gibbed.vel;
|
|
if ( delay > 0 )
|
|
{
|
|
delay--;
|
|
return;
|
|
}
|
|
A_StartSound("misc/gibber");
|
|
BurstGibs();
|
|
if ( reactiontime <= 0 )
|
|
Destroy();
|
|
}
|
|
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
Radius 32;
|
|
Height 16;
|
|
}
|
|
}
|
|
|
|
// bare actors used for copying blood color to vanilla monsters
|
|
Class GreenBloodReference : Actor
|
|
{
|
|
Default
|
|
{
|
|
BloodColor "Green";
|
|
}
|
|
}
|
|
Class BlueBloodReference : Actor
|
|
{
|
|
Default
|
|
{
|
|
BloodColor "Blue";
|
|
}
|
|
}
|
|
|
|
// corpse thump handler
|
|
Class CorpseFallTracker : Thinker
|
|
{
|
|
Actor mybody;
|
|
double lastvelz;
|
|
bool wasflying;
|
|
|
|
static void TrackBody( Actor b )
|
|
{
|
|
if ( !b ) return;
|
|
let cft = new("CorpseFallTracker");
|
|
cft.ChangeStatNum(STAT_USER);
|
|
cft.mybody = b;
|
|
cft.lastvelz = b.vel.z;
|
|
cft.wasflying = ((b.pos.z>b.floorz)&&b.TestMobjZ());
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !mybody )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
// play fall thumps
|
|
bool isflying = ((mybody.pos.z>mybody.floorz)&&mybody.TestMobjZ());
|
|
if ( wasflying && !isflying && (lastvelz < -10) )
|
|
mybody.A_StartSound("misc/bodythump",CHAN_DAMAGE,CHANF_OVERLAP);
|
|
wasflying = isflying;
|
|
lastvelz = mybody.vel.z;
|
|
// wait until body is dead on floor and at the last state of animation
|
|
if ( (mybody.Health > 0) || isflying || (mybody.tics != -1) || (mybody.vel.length() > 0) )
|
|
return;
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
Class SWWMGoreHandler : EventHandler
|
|
{
|
|
override void CheckReplacement( ReplaceEvent e )
|
|
{
|
|
// only replace vanilla blood if no other gore mod is doing it
|
|
if ( (e.Replacee == "Blood") && (!e.Replacement || e.Replacement == "Blood") && swwm_blood )
|
|
e.Replacement = "mkBlood";
|
|
}
|
|
|
|
override void WorldThingSpawned( WorldEvent e )
|
|
{
|
|
// vanilla blood color changes
|
|
if ( (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "HellKnight") )
|
|
{
|
|
let gb = Actor.Spawn("GreenBloodReference");
|
|
e.Thing.CopyBloodColor(gb);
|
|
gb.Destroy();
|
|
}
|
|
else if ( e.Thing.GetClass() == "Cacodemon" )
|
|
{
|
|
let bb = Actor.Spawn("BlueBloodReference");
|
|
e.Thing.CopyBloodColor(bb);
|
|
bb.Destroy();
|
|
}
|
|
}
|
|
|
|
override void WorldThingDamaged( WorldEvent e )
|
|
{
|
|
if ( e.Thing.Health > 0 ) return;
|
|
// only do special handling if they use our blood
|
|
if ( (e.Thing.GetBloodType(0) != "mkBlood") || e.Thing.bNOBLOOD )
|
|
return;
|
|
CorpseFallTracker.TrackBody(e.Thing);
|
|
bool b;
|
|
Actor a;
|
|
// special handling of some monsters
|
|
if ( e.Thing.GetClass() == "Cyberdemon" )
|
|
{
|
|
[b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR);
|
|
if ( !b ) return;
|
|
mkGibber(a).gibbed = e.Thing;
|
|
mkGibber(a).delay = 40;
|
|
a.A_SetSize(e.Thing.default.radius,e.Thing.default.height);
|
|
return;
|
|
}
|
|
else if ( e.Thing.GetClass() == "SpiderMastermind" )
|
|
{
|
|
[b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR);
|
|
if ( !b ) return;
|
|
mkGibber(a).gibbed = e.Thing;
|
|
mkGibber(a).delay = 60;
|
|
a.A_SetSize(e.Thing.default.radius,e.Thing.default.height);
|
|
return;
|
|
}
|
|
// override gibbing
|
|
int gibhealth = e.Thing.GetGibHealth();
|
|
if ( !e.Thing.bDONTGIB && (e.Thing.FindState("XDeath",true) || e.Thing.FindState("Death.Extreme",true)) && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH) )
|
|
{
|
|
[b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR);
|
|
if ( !b ) return;
|
|
mkGibber(a).gibbed = e.Thing;
|
|
a.A_SetSize(e.Thing.default.radius,e.Thing.default.height);
|
|
}
|
|
}
|
|
}
|