1091 lines
27 KiB
Text
1091 lines
27 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 QuadExplLight3 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "QuadExpl";
|
|
Args 0,0,0,300;
|
|
ReactionTime 30;
|
|
}
|
|
}
|
|
|
|
Class QuadFlare : SWWMNonInteractiveActor
|
|
{
|
|
bool bBig;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Alpha .5;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
prev = pos;
|
|
if ( freezetics > 0 )
|
|
{
|
|
freezetics--;
|
|
return;
|
|
}
|
|
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 : SWWMNonInteractiveActor
|
|
{
|
|
Mixin SWWMMinimalMovingTick;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Alpha .5;
|
|
Scale 1.5;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
}
|
|
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));
|
|
}
|
|
void A_Flame()
|
|
{
|
|
vel *= .9;
|
|
A_SetScale(scale.x*.96);
|
|
A_FadeOut(.05);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XFLM ABCDEFGHIJKLMNOPQRST 1 Bright A_Flame();
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
Class QuadEmber : SWWMNonInteractiveActor
|
|
{
|
|
Vector3 freq, amp, ph;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale .3;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
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 ( freezetics > 0 )
|
|
{
|
|
freezetics--;
|
|
return;
|
|
}
|
|
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);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
QEMB # -1 Bright;
|
|
Stop;
|
|
Death:
|
|
QEMB # -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadExplRing : SWWMNonInteractiveActor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 1.2;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG8 ACEGIKMOQSUW 1 Bright A_SetScale(scale.x*1.05);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadProj : Actor
|
|
{
|
|
meta 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] = SWWMUtility.GetAxes(angle,pitch,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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*.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),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,120000+special2,150,40,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,100+special1,0,150,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,200+special1,0,120,40,DE_HOWL|DE_NOSPLASH,ignoreme:tracer);
|
|
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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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;
|
|
+NOFRICTION;
|
|
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;
|
|
+NOFRICTION;
|
|
Gravity .35;
|
|
BounceFactor 1.;
|
|
Radius 2;
|
|
Height 4;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
reactiontime = Random[ExploS](4,8)+special1;
|
|
double ang, pt;
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,90);
|
|
speed = FRandom[ExploS](12.,32.);
|
|
vel = SWWMUtility.Vec3FromAngles(ang,pt)*speed;
|
|
}
|
|
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 = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*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.+special1));
|
|
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 QuadExplArm2 : QuadExplArm
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
Actor.PostBeginPlay();
|
|
reactiontime = Random[ExploS](4,8)+special1;
|
|
speed = FRandom[ExploS](40.,80.)+special2;
|
|
vel = SWWMUtility.Vec3FromAngles(angle,pitch)*speed;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1
|
|
{
|
|
Spawn("QuadExplTrail2",pos);
|
|
if ( !(ReactionTime%2) )
|
|
{
|
|
SWWMUtility.DoExplosion(self,0,80000+reactiontime*5000,120+6*reactiontime,50,DE_BLAST|DE_EXTRAZTHRUST,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,60+reactiontime*5,0,120+6*reactiontime,50,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,80+reactiontime*10,0,100+4*reactiontime,50,DE_HOWL|DE_NOSPLASH,ignoreme:tracer);
|
|
}
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,5);
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel+vel*.6;
|
|
s.special1 = Random[ExploS](2,4);
|
|
s.scale *= 3.2;
|
|
s.alpha *= .1+.4*(ReactionTime/(12.+special1));
|
|
int numpt = Random[Quadravol](1,5);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.7;
|
|
}
|
|
A_CountDown();
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class QuadExplTrail : SWWMNonInteractiveActor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+FORCEXYBILLBOARD;
|
|
Scale 1.2;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX0 ACEGIKMOQS 1 Bright A_SetScale(scale.x*1.03);
|
|
Stop;
|
|
}
|
|
}
|
|
Class QuadExplTrail2 : QuadExplTrail
|
|
{
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX0 ABCDEFGHIJKLMNOPQRS 1 Bright A_SetScale(scale.x*1.02);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadExplRing2 : QuadExplRing
|
|
{
|
|
Default
|
|
{
|
|
Scale 2.;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG8 ABCDEFGHIJKLMNOPQRSTUVWX 1 Bright A_SetScale(scale.x*1.04);
|
|
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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*.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),280000+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,180000+special2,240,80,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,200+special1,0,240,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,400+special1,0,200,80,DE_HOWL|DE_NOSPLASH,ignoreme:tracer);
|
|
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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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 = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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 QuadProjSub : QuadProj
|
|
{
|
|
Default
|
|
{
|
|
Scale .3;
|
|
Radius 2;
|
|
Height 2;
|
|
Speed 30;
|
|
QuadProj.Drift 10.;
|
|
QuadProj.AccelRate 100;
|
|
QuadProj.MaxSpeed 150;
|
|
}
|
|
override void A_QuadTrail()
|
|
{
|
|
let s = Spawn("QuadTrail",pos);
|
|
s.scale *= .5;
|
|
s.vel = vel*.3;
|
|
s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*.4;
|
|
s.vel += vel*.4;
|
|
s.alpha *= .2;
|
|
int numpt = Random[Quadravol](1,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.4;
|
|
}
|
|
}
|
|
override void A_QuadExplode()
|
|
{
|
|
A_StopSound(CHAN_BODY);
|
|
Scale *= 1.5;
|
|
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),100000);
|
|
}
|
|
A_QuakeEx(2,2,2,10,0,300,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:100,rollintensity:.3);
|
|
SWWMUtility.DoExplosion(self,0,70000,120,40,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,50,0,120,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,150,0,100,40,DE_HOWL|DE_NOSPLASH,ignoreme:tracer);
|
|
A_StartSound("quadshot/hit",CHAN_WEAPON,attenuation:.8,pitch:1.2);
|
|
A_AlertMonsters(swwm_uncapalert?0:800);
|
|
Spawn("QuadExplLight",pos);
|
|
int numpt = Random[Quadravol](6,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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](5,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*FRandom[Quadravol](4,16);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Quadravol](2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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,100,SWWMUtility.Vec3FromAngles(angle,pitch));
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
TNT1 A 0 A_QuadExplode();
|
|
XEX0 ACEGIKMOQS 1 Bright A_SetScale(scale.x*1.1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadProjSub2 : QuadProj
|
|
{
|
|
Default
|
|
{
|
|
Scale .3;
|
|
Radius 4;
|
|
Height 4;
|
|
Speed 30;
|
|
QuadProj.Drift 3.;
|
|
QuadProj.AccelRate 80;
|
|
QuadProj.MaxSpeed 120;
|
|
}
|
|
override void A_QuadTrail()
|
|
{
|
|
let s = Spawn("QuadTrail",pos);
|
|
s.scale *= .3;
|
|
s.vel = vel*.3;
|
|
s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*.4;
|
|
s.vel += vel*.4;
|
|
s.alpha *= .2;
|
|
int numpt = Random[Quadravol](1,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.4;
|
|
}
|
|
}
|
|
override void A_QuadExplode()
|
|
{
|
|
A_StopSound(CHAN_BODY);
|
|
Scale *= 1.5;
|
|
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),100000);
|
|
}
|
|
A_QuakeEx(2,2,2,10,0,200,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:80,rollintensity:.2);
|
|
SWWMUtility.DoExplosion(self,0,60000,120,40,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,80,0,120,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,180,0,100,40,DE_HOWL|DE_NOSPLASH,ignoreme:tracer);
|
|
A_StartSound("quadshot/hit",CHAN_WEAPON,attenuation:.6,pitch:1.1);
|
|
A_AlertMonsters(swwm_uncapalert?0:600);
|
|
Spawn("QuadExplLight",pos);
|
|
int numpt = Random[Quadravol](6,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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](5,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*FRandom[Quadravol](4,16);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Quadravol](2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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,120,SWWMUtility.Vec3FromAngles(angle,pitch));
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
TNT1 A 0 A_QuadExplode();
|
|
XEX0 ACEGIKMOQS 1 Bright A_SetScale(scale.x*1.1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadExplRing3 : QuadExplRing
|
|
{
|
|
Default
|
|
{
|
|
Scale 2.5;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG8 ABCDEFGHIJKLMNOPQRSTUVWX 1 Bright A_SetScale(scale.x*1.05);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class QuadProj3 : QuadProj
|
|
{
|
|
Default
|
|
{
|
|
Scale 1.;
|
|
Radius 10;
|
|
Height 10;
|
|
Speed 20;
|
|
QuadProj.Drift .8;
|
|
QuadProj.AccelRate 40;
|
|
QuadProj.MaxSpeed 60;
|
|
}
|
|
override void A_QuadTrail()
|
|
{
|
|
let s = Spawn("QuadTrail",pos);
|
|
s.scale *= 1.2;
|
|
s.vel = vel*.4;
|
|
s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*.4;
|
|
s.vel += vel*.6;
|
|
s.alpha *= .8;
|
|
s.special1 = 1;
|
|
int numpt = Random[Quadravol](5,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
s = Spawn("QuadEmber",pos);
|
|
s.vel += vel*.6;
|
|
}
|
|
}
|
|
override void A_QuadExplode()
|
|
{
|
|
A_StopSound(CHAN_BODY);
|
|
Scale *= 3.;
|
|
A_SprayDecal("ShockMarkHuge",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),350000+special2);
|
|
}
|
|
if ( tracer ) SWWMUtility.DoKnockback(tracer,-x+(0,0,.1),bAMBUSH?180000:800000);
|
|
A_QuakeEx(7,7,7,35,0,1200,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:600,rollintensity:1.2);
|
|
SWWMUtility.DoExplosion(self,0,200000+special2,300,120,DE_BLAST|DE_EXTRAZTHRUST);
|
|
SWWMUtility.DoExplosion(self,300+special1,0,300,0,DE_QUADRAVOL|DE_NOSPLASH,ignoreme:tracer);
|
|
SWWMUtility.DoExplosion(self,500+special1,0,240,120,DE_HOWL|DE_NOSPLASH,ignoreme:tracer);
|
|
A_StartSound("quadshot/twohit",CHAN_WEAPON,attenuation:.4,pitch:.9);
|
|
A_StartSound("quadshot/twohit",CHAN_VOICE,attenuation:.3,pitch:.8);
|
|
A_StartSound("quadshot/extrahit",CHAN_ITEM,attenuation:.2,pitch:1.1);
|
|
A_AlertMonsters(swwm_uncapalert?0:3500);
|
|
Spawn("QuadExplLight3",pos);
|
|
Spawn("QuadExplRing3",pos);
|
|
int numpt = Random[Quadravol](25,35);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*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](20,25);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*FRandom[Quadravol](4,16);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Quadravol](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Quadravol](0,360),FRandom[Quadravol](-90,90))*FRandom[Quadravol](6,12);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Quadravol](0.9,1.8);
|
|
}
|
|
numpt = Random[Quadravol](16,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("QuadExplArm",pos);
|
|
s.target = target;
|
|
s.tracer = tracer;
|
|
s.special1 = 10;
|
|
}
|
|
for ( int j=-90; j<=90; j+=30 ) for ( int i=0; i<360; i+=60 )
|
|
{
|
|
double ang = i+FRandom[ExploS](-30,30);
|
|
double pt = j+FRandom[ExploS](-15,15);
|
|
// skip if directly hitting a wall
|
|
if ( LineTrace(ang,40,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
let s = Spawn("QuadProjSub",pos);
|
|
s.target = target;
|
|
s.tracer = tracer;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.vel = SWWMUtility.Vec3FromAngles(ang,pt)*s.speed*FRandom[ExploS](.8,1.2);
|
|
s.bHITOWNER = !tracer;
|
|
if ( (j == -90) || (j == 90) ) break; // only one per pole
|
|
}
|
|
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.08);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class OnFireLight : PointLightFlickerRandomAttenuated
|
|
{
|
|
OnFire of;
|
|
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !of || !of.Owner )
|
|
{
|
|
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.Owner.radius,of.Owner.height)*2.5+40+clamp(of.Amount/4,0,120));
|
|
Args[4] = args[3]+8;
|
|
SetOrigin(of.Owner.Vec3Offset(0,0,of.Owner.Height/2),true);
|
|
}
|
|
}
|
|
|
|
Class OnFire : Inventory
|
|
{
|
|
Actor instigator, lite;
|
|
int cnt;
|
|
double oangle;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_QUADRAVOL";
|
|
Inventory.Amount 1;
|
|
Inventory.MaxAmount 500;
|
|
+INVENTORY.KEEPDEPLETED; // since our amount can go below 0, we need special cleanup
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNTOSSABLE;
|
|
+NOEXTREMEDEATH;
|
|
}
|
|
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
cnt = 1;
|
|
lite = Spawn("OnFireLight",other.pos);
|
|
lite.specialf1 = 3;
|
|
OnFireLight(lite).of = self;
|
|
}
|
|
|
|
override void OwnerDied()
|
|
{
|
|
Super.OwnerDied();
|
|
amount = min(amount,100);
|
|
}
|
|
|
|
override void PreTravelled()
|
|
{
|
|
Super.PreTravelled();
|
|
// debuff disappears between levels
|
|
Destroy();
|
|
}
|
|
|
|
override int DoSpecialDamage( Actor target, int Damage, Name DamageType )
|
|
{
|
|
if ( target == Owner ) return Damage;
|
|
// spread ourselves
|
|
// note: cannot spread to Demolitionist
|
|
if ( !(target is 'Demolitionist') )
|
|
{
|
|
let t = OnFire(target.FindInventory("OnFire"));
|
|
if ( !t )
|
|
{
|
|
t = Apply(target,instigator,min(Damage,int(Amount*.6))); // prevent "escalating" spread
|
|
t.cnt = 15; // long delay
|
|
}
|
|
else if ( t.Amount < int(Amount*.6) ) t.Amount = min(t.Amount+Damage,int(Amount*.6)); // prevent "escalating" spread
|
|
t.instigator = instigator;
|
|
}
|
|
return clamp(int(Damage*.15),1,50); // reduced direct damage
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( Owner is 'Demolitionist' ) amount = min(amount-1,100); // Demo's body puts out fire faster
|
|
if ( !(level.maptime%3) )
|
|
amount--;
|
|
if ( Owner.player ) amount -= int(abs(actor.deltaangle(Owner.angle,oangle))/30);
|
|
oangle = Owner.angle;
|
|
if ( amount < -30 )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( cnt > 0 ) cnt--;
|
|
else
|
|
{
|
|
cnt = 10;
|
|
if ( Owner.bSHOOTABLE && (Owner.Health > 0) && (amount > 0) )
|
|
{
|
|
int flg = DMG_THRUSTLESS;
|
|
if ( Owner is 'Centaur' ) flg |= DMG_FOILINVUL; // you're on fire, that shield is worthless
|
|
Owner.DamageMobj(self,instigator,clamp(int(amount*.15),1,50),'Fire',flg);
|
|
if ( Owner && Owner.bISMONSTER && !Random[FlameT](0,3) )
|
|
Owner.Howl();
|
|
}
|
|
if ( !Owner )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
// damage nearby actors
|
|
if ( amount > 0 ) SWWMUtility.DoExplosion(Owner,amount,0,Owner.radius+40+amount/5,Owner.radius+20,DE_NOBLEED|DE_NOSPLASH|DE_HOWL|DE_CENTERHEIGHT|DE_NONEXPLOSIVE,'Fire',null,DMG_THRUSTLESS,instigator,self);
|
|
}
|
|
double mult = max(Owner.radius,Owner.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 tpos = Owner.Vec3Offset(FRandom[FlameT](-Owner.radius,Owner.radius)*.8,FRandom[FlameT](-Owner.radius,Owner.radius)*.8,FRandom[FlameT](Owner.height*.2,Owner.height*.8));
|
|
double ang = FRandom[FlameT](0,360);
|
|
double pt = FRandom[FlameT](-90,90);
|
|
if ( amount > 0 )
|
|
{
|
|
let c = Spawn("OnFireTrail",tpos);
|
|
c.scale *= max(.35,mult*.6);
|
|
c.vel = Owner.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.5,2.)*c.scale.x;
|
|
}
|
|
if ( Random[FlameT](0,3) ) continue;
|
|
let s = Spawn("SWWMHalfSmoke",tpos);
|
|
s.scale *= max(.35,mult*.5);
|
|
s.alpha *= min(amount+30,100)*.005;
|
|
s.vel = Owner.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.2,.6)*s.scale.x;
|
|
}
|
|
}
|
|
|
|
static OnFire Apply( Actor victim, Actor instigator, int amount )
|
|
{
|
|
let t = OnFire(victim.FindInventory("OnFire"));
|
|
if ( t )
|
|
{
|
|
t.instigator = instigator;
|
|
t.amount = min(t.maxamount,t.amount+amount);
|
|
t.cnt = min(t.cnt,5);
|
|
return t;
|
|
}
|
|
t = OnFire(Spawn("ONFire"));
|
|
t.AttachToOwner(victim);
|
|
t.instigator = instigator;
|
|
t.amount = min(t.maxamount,amount);
|
|
t.cnt = 1;
|
|
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 clearscope OnFire IsOnFire( Actor victim )
|
|
{
|
|
let t = OnFire(victim.FindInventory("OnFire"));
|
|
if ( t && (t.amount > 0) ) return t;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Class OnFireTrail : SWWMNonInteractiveActor
|
|
{
|
|
Mixin SWWMMinimalMovingWaterTick;
|
|
|
|
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));
|
|
}
|
|
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 = SWWMUtility.Vec3FromAngles(FRandom[FlameT](0,360),FRandom[FlameT](-90,90))*.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);
|
|
}
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Speed 2;
|
|
Alpha .3;
|
|
Scale .6;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XFLM AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTT 1 Bright A_Flame();
|
|
Loop;
|
|
}
|
|
}
|