821 lines
19 KiB
Text
821 lines
19 KiB
Text
// Quadravol projectiles and effects
|
|
|
|
Class QuadravolCasing : SWWMCasing
|
|
{
|
|
Default
|
|
{
|
|
BounceSound "quadshot/casing";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
heat = 0;
|
|
}
|
|
}
|
|
|
|
Class QuadExplLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "QuadExpl";
|
|
Args 0,0,0,150;
|
|
ReactionTime 20;
|
|
}
|
|
}
|
|
Class QuadExplLight2 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "QuadExpl";
|
|
Args 0,0,0,250;
|
|
ReactionTime 25;
|
|
}
|
|
}
|
|
|
|
Class QuadFlare : Actor
|
|
{
|
|
bool bBig;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
Alpha .5;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !master || !master.bMISSILE )
|
|
{
|
|
if ( !bBig )
|
|
{
|
|
bBig = true;
|
|
Scale *= 3.;
|
|
}
|
|
Scale *= .97;
|
|
A_FadeOut(.03);
|
|
return;
|
|
}
|
|
SetOrigin(master.pos,true);
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
QFLR A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
Alpha .5;
|
|
Scale 1.5;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
roll = FRandom[ExploS](0,360);
|
|
SetState(SpawnState+Random[ExploS](0,19));
|
|
}
|
|
action void A_Flame()
|
|
{
|
|
vel *= .9;
|
|
A_SetScale(scale.x*.96);
|
|
A_FadeOut(.05);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XFLM ABCDEFGHIJKLMNOPQRST 1 Bright A_Flame();
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
Class QuadEmber : Actor
|
|
{
|
|
Vector3 freq, amp, ph;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0;
|
|
Scale .3;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Scale *= FRandom[ExploS](.5,1.5);
|
|
double ang = FRandom[ExploS](0,360),
|
|
pt = FRandom[ExploS](-90,90);
|
|
vel = SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[ExploS](4.,8.);
|
|
freq = (FRandom[ExploS](.5,3.),FRandom[ExploS](.5,3.),FRandom[ExploS](.5,3.));
|
|
amp = (FRandom[ExploS](.5,2.),FRandom[ExploS](.5,2.),FRandom[ExploS](.5,2.));
|
|
ph = (FRandom[ExploS](0.,360.),FRandom[ExploS](0.,360.),FRandom[ExploS](0.,360.));
|
|
specialf1 = FRandom[ExploS](.98,.99);
|
|
specialf2 = FRandom[ExploS](.98,.99);
|
|
}
|
|
override void Tick()
|
|
{
|
|
prev = pos;
|
|
if ( isFrozen() ) return;
|
|
if ( !InStateSequence(CurState,FindState("Death")) )
|
|
{
|
|
vel *= .95;
|
|
vel += .2*(sin(ph.x)*amp.x,sin(ph.y)*amp.y,sin(ph.z)*amp.z);
|
|
vel.z -= .05*clamp(2.-amp.length(),0.,2.);
|
|
ph.x += freq.x*(360./GameTicRate);
|
|
ph.y += freq.y*(360./GameTicRate);
|
|
ph.z += freq.z*(360./GameTicRate);
|
|
freq *= specialf1;
|
|
amp *= specialf2;
|
|
Vector3 newpos = level.Vec3Offset(pos,vel);
|
|
if ( !level.IsPointInLevel(newpos) )
|
|
{
|
|
vel *= 0;
|
|
SetStateLabel("Death");
|
|
return;
|
|
}
|
|
SetOrigin(newpos,true);
|
|
UpdateWaterLevel();
|
|
if ( waterlevel > 0 )
|
|
{
|
|
vel *= 0;
|
|
SetStateLabel("Death");
|
|
return;
|
|
}
|
|
A_FadeOut(FRandom[ExploS](.002,.005));
|
|
}
|
|
else A_FadeOut(FRandom[ExploS](.02,.05));
|
|
frame = clamp(int(round(4-alpha*4)),0,4);
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
QEMB # -1 Bright;
|
|
Stop;
|
|
Death:
|
|
QEMB # -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadExplRing : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 1.2;
|
|
Radius .1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG8 ACEGIKMOQSUW 1 Bright A_SetScale(scale.x*1.05);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadProj : Actor
|
|
{
|
|
double drift, accelrate, maxspeed;
|
|
|
|
Property Drift: drift;
|
|
Property AccelRate: accelrate;
|
|
Property MaxSpeed: maxspeed;
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("quadshot/fly",CHAN_BODY,CHANF_LOOP);
|
|
let t = Spawn("QuadFlare",pos);
|
|
t.master = self;
|
|
t.scale = scale*2.;
|
|
}
|
|
|
|
// acceleration, drift and speed limit
|
|
void A_QuadMove()
|
|
{
|
|
A_QuadTrail();
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
double a = FRandom[Quadravol](0.,360.), s = FRandom[Quadravol](0.,drift);
|
|
vel += x*(accelrate/GameTicRate);
|
|
vel += SWWMUtility.CircleOffset(y,z,a,s);
|
|
double magvel = vel.length();
|
|
Vector3 dir = (magvel<=0.)?x:(vel/magvel);
|
|
if ( magvel > maxspeed ) magvel = maxspeed;
|
|
vel = dir*magvel;
|
|
speed = magvel;
|
|
}
|
|
|
|
virtual void A_QuadTrail()
|
|
{
|
|
let s = Spawn("QuadTrail",pos);
|
|
s.scale *= .6;
|
|
s.vel = vel*.2;
|
|
s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = (FRandom[Quadravol](-.4,.4),FRandom[Quadravol](-.4,.4),FRandom[Quadravol](-.4,.4));
|
|
s.vel += vel*.3;
|
|
s.alpha *= .4;
|
|
int numpt = Random[Quadravol](5,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.3;
|
|
}
|
|
}
|
|
|
|
virtual void A_QuadExplode()
|
|
{
|
|
A_StopSound(CHAN_BODY);
|
|
Scale *= 2.;
|
|
A_SprayDecal("ShockMark",50);
|
|
Vector3 x = SWWMUtility.Vec3FromAngles(angle,pitch);
|
|
if ( master && ((master.pos.z <= master.floorz) || !master.TestMobjZ()) )
|
|
{
|
|
Vector3 rel = level.Vec3Diff(master.pos,pos);
|
|
double hdiff = 1.-2.*clamp((rel.z-4.)/master.height,0.,.5);
|
|
SWWMUtility.DoKnockback(master,x+(0,0,hdiff*.5),200000+special2);
|
|
}
|
|
if ( tracer ) SWWMUtility.DoKnockback(tracer,-x+(0,0,.1),bAMBUSH?150000:500000);
|
|
A_QuakeEx(3,3,3,20,0,500,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:200,rollintensity:.6);
|
|
SWWMUtility.DoExplosion(self,0,80000+special2,240,80,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,100+special1,0,240,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
if ( SWWMUtility.DoExplosion(self,150+special1,0,200,80,DE_HOWL|DE_NOSPLASH,ignoreme:tracer) && bAMBUSH && target )
|
|
SWWMUtility.AchievementProgressInc("roast",1,target.player);
|
|
A_StartSound("quadshot/hit",CHAN_WEAPON,attenuation:.6);
|
|
A_StartSound("quadshot/hit",CHAN_VOICE,attenuation:.4);
|
|
A_AlertMonsters(swwm_uncapalert?0:1500);
|
|
Spawn("QuadExplLight",pos);
|
|
Spawn("QuadExplRing",pos);
|
|
int numpt = Random[Quadravol](12,18);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1)).unit()*FRandom[Quadravol](2,8);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.special1 = Random[Quadravol](2,3);
|
|
s.scale *= 4.;
|
|
s.alpha *= .3;
|
|
}
|
|
numpt = Random[Quadravol](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1)).unit()*FRandom[Quadravol](4,16);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Quadravol](4,8);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1)).unit()*FRandom[Quadravol](6,12);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Quadravol](0.9,1.8);
|
|
}
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,150,SWWMUtility.Vec3FromAngles(angle,pitch));
|
|
}
|
|
|
|
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
|
{
|
|
// from melee combo
|
|
if ( bAMBUSH ) return StringTable.Localize("$O_QUADRAVOL2");
|
|
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
|
}
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_QUADRAVOL";
|
|
DamageType "Fire";
|
|
Scale .5;
|
|
Radius 6;
|
|
Height 6;
|
|
Speed 60;
|
|
QuadProj.Drift .15;
|
|
QuadProj.AccelRate 30;
|
|
QuadProj.MaxSpeed 120;
|
|
PROJECTILE;
|
|
+FORCEXYBILLBOARD;
|
|
+EXPLODEONWATER;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+HITMASTER;
|
|
RenderStyle "Add";
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
QFBL ABCDEFGHIJ 1 Bright A_QuadMove();
|
|
Loop;
|
|
Death:
|
|
TNT1 A 0 A_QuadExplode();
|
|
XEX0 ABCDEFGHIJKLMNOPQRS 1 Bright A_SetScale(scale.x*1.05);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadExplArm : Actor
|
|
{
|
|
Default
|
|
{
|
|
PROJECTILE;
|
|
+THRUACTORS;
|
|
+BOUNCEONWALLS;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+CANBOUNCEWATER;
|
|
+NODAMAGETHRUST;
|
|
+FORCERADIUSDMG;
|
|
-NOGRAVITY;
|
|
Gravity .35;
|
|
BounceFactor 1.;
|
|
Radius 2;
|
|
Height 4;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
reactiontime = Random[ExploS](4,8);
|
|
double ang, pt;
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,90);
|
|
vel = SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[ExploS](12.,32.);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1
|
|
{
|
|
Spawn("QuadExplTrail",pos);
|
|
if ( !(ReactionTime%2) )
|
|
SWWMUtility.DoExplosion(self,8+reactiontime*3,0,40+5*reactiontime,20,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel+vel*.3;
|
|
s.special1 = Random[ExploS](1,3);
|
|
s.scale *= 3.;
|
|
s.alpha *= .1+.4*(ReactionTime/8.);
|
|
int numpt = Random[Quadravol](1,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.4;
|
|
}
|
|
A_CountDown();
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class QuadExplTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale 1.2;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX0 ACEGIKMOQS 1 Bright A_SetScale(scale.x*1.03);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadExplRing2 : QuadExplRing
|
|
{
|
|
Default
|
|
{
|
|
Scale 1.6;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG8 ABCDEFGHIJKLMNOPQRSTUVWX 1 Bright A_SetScale(scale.x*1.03);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadProj2 : QuadProj
|
|
{
|
|
Default
|
|
{
|
|
Scale .85;
|
|
Radius 8;
|
|
Height 8;
|
|
Speed 40;
|
|
QuadProj.Drift .25;
|
|
QuadProj.AccelRate 20;
|
|
QuadProj.MaxSpeed 80;
|
|
}
|
|
override void A_QuadTrail()
|
|
{
|
|
let s = Spawn("QuadTrail",pos);
|
|
s.scale *= .8;
|
|
s.vel = vel*.3;
|
|
s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = (FRandom[Quadravol](-.4,.4),FRandom[Quadravol](-.4,.4),FRandom[Quadravol](-.4,.4));
|
|
s.vel += vel*.4;
|
|
s.alpha *= .6;
|
|
int numpt = Random[Quadravol](5,25);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.4;
|
|
}
|
|
}
|
|
override void A_QuadExplode()
|
|
{
|
|
A_StopSound(CHAN_BODY);
|
|
Scale *= 2.4;
|
|
A_SprayDecal("ShockMarkBig",50);
|
|
Vector3 x = SWWMUtility.Vec3FromAngles(angle,pitch);
|
|
if ( master && ((master.pos.z <= master.floorz) || !master.TestMobjZ()) )
|
|
{
|
|
Vector3 rel = level.Vec3Diff(master.pos,pos);
|
|
double hdiff = 1.-2.*clamp((rel.z-4.)/master.height,0.,.5);
|
|
SWWMUtility.DoKnockback(master,x+(0,0,hdiff*.5),250000+special2);
|
|
}
|
|
if ( tracer ) SWWMUtility.DoKnockback(tracer,-x+(0,0,.1),bAMBUSH?160000:600000);
|
|
A_QuakeEx(5,5,5,25,0,900,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:400,rollintensity:.8);
|
|
SWWMUtility.DoExplosion(self,0,100000+special2,480,120,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,200+special1,0,480,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
if ( SWWMUtility.DoExplosion(self,300+special1,0,400,120,DE_HOWL|DE_NOSPLASH,ignoreme:tracer) && bAMBUSH && target )
|
|
SWWMUtility.AchievementProgressInc("roast",1,target.player);
|
|
A_StartSound("quadshot/twohit",CHAN_WEAPON,attenuation:.5);
|
|
A_StartSound("quadshot/twohit",CHAN_VOICE,attenuation:.25);
|
|
A_AlertMonsters(swwm_uncapalert?0:2500);
|
|
Spawn("QuadExplLight2",pos);
|
|
Spawn("QuadExplRing2",pos);
|
|
int numpt = Random[Quadravol](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1)).unit()*FRandom[Quadravol](2,12);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.special1 = Random[Quadravol](2,3);
|
|
s.scale *= 4.;
|
|
s.alpha *= .3;
|
|
}
|
|
numpt = Random[Quadravol](15,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1)).unit()*FRandom[Quadravol](4,16);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Quadravol](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1),FRandom[Quadravol](-1,1)).unit()*FRandom[Quadravol](6,12);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Quadravol](0.9,1.8);
|
|
}
|
|
numpt = Random[Quadravol](12,16);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("QuadExplArm",pos);
|
|
s.target = target;
|
|
s.tracer = tracer;
|
|
}
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,300,SWWMUtility.Vec3FromAngles(angle,pitch));
|
|
}
|
|
|
|
States
|
|
{
|
|
Death:
|
|
TNT1 A 0 A_QuadExplode();
|
|
XEX0 ABCDEFGHIJKLMNOPQRS 1 Bright A_SetScale(scale.x*1.065);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class OnFireLight : PointLightFlickerRandomAttenuated
|
|
{
|
|
OnFire of;
|
|
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !of || !of.victim )
|
|
{
|
|
A_StopSound(CHAN_VOICE);
|
|
Destroy();
|
|
return;
|
|
}
|
|
Args[0] = clamp(of.Amount*4,0,255);
|
|
Args[1] = clamp(of.Amount*2,0,160);
|
|
Args[2] = clamp(of.Amount/2,0,24);
|
|
Args[3] = int(max(of.victim.radius,of.victim.height)*2.5+40+clamp(of.amount/4,0,120));
|
|
Args[4] = args[3]+8;
|
|
SetOrigin(of.Victim.Vec3Offset(0,0,of.Victim.Height/2),true);
|
|
}
|
|
}
|
|
|
|
Class OnFire : Thinker
|
|
{
|
|
Actor victim, instigator, lite;
|
|
int amount, cnt;
|
|
double oangle;
|
|
|
|
override void Tick()
|
|
{
|
|
if ( level.isFrozen() ) return;
|
|
if ( !victim )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( victim.waterlevel > 0 )
|
|
{
|
|
if ( lite ) lite.Destroy();
|
|
amount -= int(victim.waterlevel**2);
|
|
}
|
|
if ( victim is 'Demolitionist' ) amount = min(amount-2,200); // Demo's body puts out fire faster
|
|
if ( victim.Health <= 0 ) amount = min(amount,100);
|
|
if ( !(level.maptime%3) )
|
|
amount--;
|
|
if ( victim.player ) amount -= int(abs(actor.deltaangle(victim.angle,oangle))/30);
|
|
oangle = victim.angle;
|
|
if ( amount < -30 )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( cnt > 0 ) cnt--;
|
|
else
|
|
{
|
|
cnt = 10;
|
|
if ( victim.bSHOOTABLE && (victim.Health > 0) && (amount > 0) )
|
|
{
|
|
int flg = DMG_THRUSTLESS;
|
|
if ( victim is 'Centaur' ) flg |= DMG_FOILINVUL; // you're on fire, that shield is worthless
|
|
Actor inflictor = instigator;
|
|
if ( instigator )
|
|
{
|
|
let q = instigator.FindInventory("Quadravol");
|
|
if ( q ) inflictor = q;
|
|
}
|
|
victim.DamageMobj(inflictor,instigator,clamp(int(amount*.15),1,50),'Fire',flg);
|
|
if ( victim.bISMONSTER && !Random[FlameT](0,3) )
|
|
victim.Howl();
|
|
}
|
|
if ( !victim )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
}
|
|
double mult = max(victim.radius,victim.height)/30.;
|
|
if ( lite ) lite.A_SoundVolume(CHAN_VOICE,min(1.,mult*amount/80.));
|
|
if ( level.maptime%5 ) return;
|
|
int numpt = clamp(int(Random[FlameT](2,4)*amount*.02),1,4);
|
|
numpt = int(clamp(numpt*mult**.5,1,5));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pos = victim.Vec3Offset(FRandom[FlameT](-victim.radius,victim.radius)*.8,FRandom[FlameT](-victim.radius,victim.radius)*.8,FRandom[FlameT](victim.height*.2,victim.height*.8));
|
|
double ang = FRandom[FlameT](0,360);
|
|
double pt = FRandom[FlameT](-90,90);
|
|
if ( amount > 0 )
|
|
{
|
|
let c = victim.Spawn("OnFireTrail",pos);
|
|
c.scale *= max(.35,mult*.6);
|
|
c.vel = victim.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.5,2.)*c.scale.x;
|
|
}
|
|
if ( Random[FlameT](0,2) ) continue;
|
|
let s = victim.Spawn("SWWMHalfSmoke",pos);
|
|
s.scale *= max(.5,mult*.75);
|
|
s.alpha *= min(amount+30,100)*.005;
|
|
s.vel = victim.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.2,.6)*s.scale.x;
|
|
}
|
|
// this is too expensive, it has to go
|
|
/*let bt = BlockThingsIterator.Create(victim);
|
|
while ( bt.Next() )
|
|
{
|
|
let t = bt.Thing;
|
|
if ( !t || !t.bSHOOTABLE || (t.Health <= 0) || (t == victim) )
|
|
continue;
|
|
double maxdist = (victim.radius+t.radius+20);
|
|
if ( (victim.Distance3DSquared(t) > maxdist*maxdist) || !victim.CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
|
|
continue;
|
|
int amt = max(1,amount/10);
|
|
let of = IsOnFire(t);
|
|
if ( of )
|
|
{
|
|
amt = min(5,amt);
|
|
of.amount = min(500,of.amount+amt);
|
|
of.cnt = min(of.cnt,5);
|
|
}
|
|
else Apply(t,instigator,amt);
|
|
}
|
|
bt.Destroy();*/
|
|
// damage nearby actors instead
|
|
Actor inflictor = instigator;
|
|
if ( instigator )
|
|
{
|
|
let q = instigator.FindInventory("Quadravol");
|
|
if ( q ) inflictor = q;
|
|
}
|
|
SWWMUtility.DoExplosion(victim,clamp(int(amount*.15),1,50),0,victim.radius+40+amount/5,0,DE_NOBLEED|DE_NOSPLASH|DE_HOWL,'Fire',instigator,DMG_THRUSTLESS,instigator,inflictor);
|
|
}
|
|
|
|
static OnFire Apply( Actor victim, Actor instigator, int amount )
|
|
{
|
|
if ( amount <= 0 ) return null;
|
|
let ti = ThinkerIterator.Create("OnFire",STAT_USER);
|
|
OnFire t;
|
|
while ( t = OnFire(ti.Next()) )
|
|
{
|
|
if ( t.victim != victim ) continue;
|
|
if ( instigator ) t.instigator = instigator;
|
|
t.amount = min(500,t.amount+amount);
|
|
t.cnt = min(t.cnt,5);
|
|
return t;
|
|
}
|
|
t = new("ONFire");
|
|
t.ChangeStatNum(STAT_USER);
|
|
t.victim = victim;
|
|
t.instigator = instigator;
|
|
t.amount = min(500,amount);
|
|
t.cnt = 1;
|
|
t.lite = Actor.Spawn("OnFireLight",victim.pos);
|
|
t.lite.specialf1 = 3;
|
|
OnFireLight(t.lite).of = t;
|
|
t.oangle = victim.angle;
|
|
double mult = max(victim.radius,victim.height)/30.;
|
|
t.lite.A_StartSound("misc/flame",CHAN_VOICE,CHANF_LOOP);
|
|
t.lite.A_SoundVolume(CHAN_VOICE,min(1.,mult*amount/80.));
|
|
return t;
|
|
}
|
|
|
|
static OnFire IsOnFire( Actor victim )
|
|
{
|
|
let ti = ThinkerIterator.Create("OnFire",STAT_USER);
|
|
OnFire t;
|
|
while ( t = OnFire(ti.Next()) )
|
|
{
|
|
if ( (t.victim != victim) || (t.amount <= 0) ) continue;
|
|
return t;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Class OnFireTrail : Actor
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
roll = FRandom[ExploS](0,360);
|
|
SetState(SpawnState+Random[ExploS](0,39));
|
|
}
|
|
action void A_Flame()
|
|
{
|
|
special1++;
|
|
if ( waterlevel > 0 )
|
|
vel *= .9;
|
|
else
|
|
{
|
|
vel *= .98;
|
|
vel.z += .1+.2*abs(scale.x);
|
|
}
|
|
if ( !Random[FlameT](0,int(40*(default.alpha-alpha))) )
|
|
{
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = (FRandom[FlameT](-.2,.2),FRandom[FlameT](-.2,.2),FRandom[FlameT](-.2,.2));
|
|
s.vel += vel*.3;
|
|
s.alpha *= alpha*.5;
|
|
s.scale *= .5+abs(scale.x*2)*(.5+special1/6.);
|
|
s.special1 = 1;
|
|
}
|
|
A_SetScale(scale.x*.98,scale.y*.98);
|
|
A_FadeOut(.01);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
UpdateWaterLevel();
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
override bool CanCollideWith( Actor Other, bool passive )
|
|
{
|
|
return false;
|
|
}
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Speed 2;
|
|
Radius 2;
|
|
Height 4;
|
|
Alpha .3;
|
|
Scale .6;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
+MBFBOUNCER;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XFLM AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTT 1 Bright A_Flame();
|
|
Loop;
|
|
}
|
|
}
|