2225 lines
59 KiB
Text
2225 lines
59 KiB
Text
// Decade Mechanics Model S-5 Biospark Carbine aka "Legacy Sparkster" (from UnSX series, also featured in SWWM series)
|
|
// Slot 7, replaces Plasma Rifle, Hellstaff, Arc of Death
|
|
|
|
Class BiosparkExplLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "SparkExpl";
|
|
}
|
|
}
|
|
Class BiosparkExplLight2 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "SparkExpl";
|
|
Args 0,0,0,500;
|
|
ReactionTime 50;
|
|
}
|
|
}
|
|
|
|
Class SparkArcLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "SparkArc";
|
|
ReactionTime 20;
|
|
}
|
|
}
|
|
Class SparkArcLightSmall : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "SparkArc";
|
|
ReactionTime 10;
|
|
}
|
|
}
|
|
Class SparkArcLightBig : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "SparkArc";
|
|
ReactionTime 40;
|
|
}
|
|
}
|
|
|
|
Class SparkBeamLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "SparkBeam";
|
|
ReactionTime 20;
|
|
Args 0,0,0,300;
|
|
}
|
|
}
|
|
|
|
Class BiosparkHitbox : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 30;
|
|
Height 60;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || !target.InStateSequence(target.CurState,target.FindState("Spawn")) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.Vec3Offset(0,0,-height*0.5),true);
|
|
}
|
|
override bool CanCollideWith( Actor other, bool passive )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
Class BigBiosparkHitbox : BiosparkHitbox
|
|
{
|
|
Default
|
|
{
|
|
Radius 80;
|
|
Height 160;
|
|
}
|
|
}
|
|
|
|
Class BigOrbiter : Actor
|
|
{
|
|
double anglevel, pitchvel;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 3.;
|
|
+NOINTERACTION;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
if ( !target || target.InStateSequence(target.CurState,target.FindState("Death")) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
angle = FRandom[Sparkster](0,360);
|
|
pitch = FRandom[Sparkster](0,360);
|
|
anglevel = FRandom[Sparkster](5,10);
|
|
pitchvel = FRandom[Sparkster](5,10);
|
|
speed = FRandom[Sparkster](20,40);
|
|
Vector3 x = swwm_CoordUtil.GetAxes(pitch,angle,0);
|
|
SetOrigin(level.Vec3Offset(target.pos,x*speed+(0,0,target.height/2)),false);
|
|
SetState(FindState("Spawn")+Random[Sparkster](0,9));
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || target.InStateSequence(target.CurState,target.FindState("Death")) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( isFrozen() ) return;
|
|
angle += anglevel;
|
|
pitch += pitchvel;
|
|
Vector3 x = swwm_CoordUtil.GetAxes(pitch,angle,0);
|
|
SetOrigin(level.Vec3Offset(target.pos,x*speed+(0,0,target.height/2)),true);
|
|
if ( tics > 0 ) tics--;
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BSPK ABCDEFGHIJ 1 Bright;
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
Class BigBiospark : Actor
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("biospark/bigspark",CHAN_VOICE,CHANF_LOOPING|CHANF_OVERLAP,1.,.6);
|
|
A_StartSound("biospark/bigspark",CHAN_VOICE,CHANF_LOOPING|CHANF_OVERLAP,1.,.6);
|
|
let h = Spawn("BigBiosparkHitbox",pos);
|
|
h.target = self;
|
|
for ( int i=0; i<special1; i++ )
|
|
{
|
|
let o = Spawn("BigOrbiter",pos);
|
|
o.target = self;
|
|
}
|
|
if ( special1 > 0 ) health = 200*special1;
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
A_StopSound(CHAN_VOICE);
|
|
Super.OnDestroy();
|
|
}
|
|
|
|
void A_BigsparkTick()
|
|
{
|
|
if ( !(special2%4) )
|
|
A_QuakeEx(Random[Sparkster](1,3),Random[Sparkster](1,3),Random[Sparkster](1,3),Random[Sparkster](4,6),0,400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:FRandom[Sparkster](.1,.3));
|
|
special2++;
|
|
int numpt = Random[ExploS](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = FRandom[ExploS](20,40);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.01,.02);
|
|
s.scale *= FRandom[ExploS](.3,1.2);
|
|
s.specialf1 = FRandom[ExploS](.9,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.06);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
numpt = Random[ExploS](0,2);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = FRandom[ExploS](40,80);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn((!(special2%8)&&!Random[Sparkster](0,10))?"BiosparkArcBig":!Random[Sparkster](0,5)?"BiosparkArc":"BiosparkArcSmall",spos);
|
|
s.target = target;
|
|
s.master = self;
|
|
s.ReactionTime += Random[Sparkster](-6,6);
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
}
|
|
// push away from nearby geometry
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
FLineTraceData d;
|
|
if ( !LineTrace(ang,40,pt,TRF_THRUACTORS|TRF_THRUHITSCAN,data:d) ) continue;
|
|
double mag = (40.-d.Distance);
|
|
vel -= (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*.02*mag;
|
|
}
|
|
double magvel = vel.length();
|
|
Vector3 dir = vel.unit();
|
|
if ( magvel <= double.epsilon ) dir = (cos(angle)*cos(pitch),sin(angle)+cos(pitch),-sin(pitch));
|
|
// wander
|
|
dir = (dir+(FRandom[Sparkster](-1,1),FRandom[Sparkster](-1,1),FRandom[Sparkster](-1,1))*FRandom[Sparkster](.05,.1)).unit();
|
|
// seek targets
|
|
if ( !(special2%5) )
|
|
{
|
|
double closest = double.infinity;
|
|
let bt = BlockThingsIterator.Create(self,8000);
|
|
while ( bt.Next() )
|
|
{
|
|
let t = bt.Thing;
|
|
double dist;
|
|
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3D(t)) > 8000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)).unit();
|
|
if ( dist > closest ) continue;
|
|
closest = dist;
|
|
tracer = t;
|
|
}
|
|
}
|
|
if ( tracer && (tracer.Health > 0) && CheckSight(tracer,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
|
|
{
|
|
Vector3 dirto = level.Vec3Diff(pos,tracer.Vec3Offset(0,0,tracer.height/2));
|
|
double dist = dirto.length();
|
|
if ( dist > 4 )
|
|
{
|
|
dirto /= dist;
|
|
dir = (dir+.2*dirto*(clamp(1.-(dist/8000.),0.,1.)**3.)).unit();
|
|
}
|
|
magvel *= 1.+.1*((dist/8000.)**.3);
|
|
}
|
|
magvel *= .985;
|
|
if ( magvel > 10. ) magvel = 10.;
|
|
if ( magvel < 2. ) magvel = 2.;
|
|
vel = magvel*dir;
|
|
angle = atan2(dir.y,dir.x);
|
|
pitch = asin(-dir.z);
|
|
// deal (proper) radius damage
|
|
let bt2 = BlockThingsIterator.Create(self,500);
|
|
while ( bt2.Next() )
|
|
{
|
|
let t = bt2.Thing;
|
|
if ( !t || !t.bSHOOTABLE ) continue;
|
|
if ( SWWMUtility.SphereIntersect(t,pos,40) )
|
|
{
|
|
t.DamageMobj(self,target,4+special1*4,'Electric');
|
|
Health--;
|
|
}
|
|
if ( SWWMUtility.SphereIntersect(t,pos,120) )
|
|
{
|
|
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2));
|
|
double dist = dirto.length();
|
|
dirto /= dist;
|
|
if ( dist > 4. ) SWWMHandler.DoKnockback(t,-dirto,clamp(120.-dist,0.,120.)*100);
|
|
}
|
|
}
|
|
Health -= 2;
|
|
if ( Health <= 0 ) ExplodeMissile();
|
|
}
|
|
|
|
void A_BigSparkExplode()
|
|
{
|
|
A_StopSound(CHAN_VOICE);
|
|
A_AlertMonsters(15000);
|
|
SWWMHandler.DoExplosion(self,450,200000,300,100);
|
|
A_QuakeEx(9,9,9,30,0,1400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollIntensity:1.5);
|
|
A_StartSound("biospark/bighit",CHAN_ITEM,attenuation:.4);
|
|
A_StartSound("biospark/bighit",CHAN_WEAPON,attenuation:.3);
|
|
A_SprayDecal("ShockMarkBig",172);
|
|
Scale *= FRandom[ExploS](3.8,4.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](40,60);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](3,20);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](2,5);
|
|
s.scale *= 4.;
|
|
s.alpha *= .6;
|
|
}
|
|
numpt = Random[ExploS](15,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](3,20);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](30,40);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](4,32);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](3,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArcBig",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,10);
|
|
}
|
|
Spawn("BiosparkExplLight2",pos);
|
|
special1 = 0;
|
|
}
|
|
|
|
void A_BigSparkSubExpl()
|
|
{
|
|
special1++;
|
|
if ( special1 > 40 ) return;
|
|
double factor = (40-special1)/40.;
|
|
double invfct = 1.-factor;
|
|
SWWMHandler.DoExplosion(self,150*factor,0.,250*invfct);
|
|
SWWMHandler.DoExplosion(self,0,-8000*factor,500*invfct);
|
|
int numpt = int(Random[ExploS](16,32)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,16)*factor;
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,5,2)*int(Random[ExploS](40,50)*factor));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 8.*factor;
|
|
s.alpha *= factor;
|
|
s.bAMBUSH = true;
|
|
}
|
|
numpt = int(Random[ExploS](8,12));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = (FRandom[ExploS](5,10)+120*invfct);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.03,.08);
|
|
s.scale *= FRandom[ExploS](.8,1.2)*factor;
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
if ( special1%2 ) return;
|
|
numpt = int(Random[ExploS](0,6)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArc",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,int(10*factor));
|
|
}
|
|
}
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
DamageType "Electric";
|
|
RenderStyle "Add";
|
|
Health 1600;
|
|
Radius 2;
|
|
Height 2;
|
|
Speed 1;
|
|
BounceFactor 1.;
|
|
WallBounceFactor 1.;
|
|
PROJECTILE;
|
|
+THRUACTORS;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FOILINVUL;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+FORCEXYBILLBOARD;
|
|
+BOUNCEONWALLS;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+CANBOUNCEWATER;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
HSPK AABBCCDDEEFFGGHHIIJJ 1 Bright A_BigsparkTick();
|
|
Loop;
|
|
Death:
|
|
TNT1 A 0 A_BigSparkExplode();
|
|
XEX2 AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSS 1 Bright A_BigSparkSubExpl();
|
|
TNT1 A 1
|
|
{
|
|
A_BigSparkSubExpl();
|
|
A_FadeOut(.02);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkBall : Actor
|
|
{
|
|
int deto;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
DamageType "Electric";
|
|
RenderStyle "Add";
|
|
Radius 3;
|
|
Height 6;
|
|
Speed 20;
|
|
PROJECTILE;
|
|
+FOILINVUL;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+EXPLODEONWATER;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("biospark/spark",CHAN_VOICE,CHANF_LOOPING);
|
|
let h = Spawn("BiosparkHitbox",pos);
|
|
h.target = self;
|
|
}
|
|
void A_SparkTick()
|
|
{
|
|
special2++;
|
|
int numpt = Random[ExploS](4,8);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = FRandom[ExploS](5,10);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.01,.02);
|
|
s.scale *= FRandom[ExploS](.3,.5);
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
numpt = Random[ExploS](0,2);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = FRandom[ExploS](5,10);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn(!Random[Sparkster](0,10)?"BiosparkArc":"BiosparkArcSmall",spos);
|
|
s.target = target;
|
|
s.master = self;
|
|
s.ReactionTime += Random[Sparkster](0,8);
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
}
|
|
double magvel = vel.length();
|
|
magvel *= 1.03;
|
|
if ( magvel > 50. ) magvel = 50.;
|
|
Vector3 dir = vel.unit();
|
|
if ( bAMBUSH )
|
|
dir = (dir+(FRandom[Sparkster](-1,1),FRandom[Sparkster](-1,1),FRandom[Sparkster](-1,1))*FRandom[Sparkster](.02,.03)).unit();
|
|
// check targets at an interval, to save on performance
|
|
if ( !(special2%5) )
|
|
{
|
|
double closest = double.infinity;
|
|
let bt = BlockThingsIterator.Create(self,500);
|
|
while ( bt.Next() )
|
|
{
|
|
let t = bt.Thing;
|
|
double dist;
|
|
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3D(t)) > 500) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)).unit();
|
|
if ( dir dot dirto < .5 ) continue; // don't seek stuff that's behind us
|
|
if ( dist > closest ) continue;
|
|
closest = dist;
|
|
tracer = t;
|
|
}
|
|
}
|
|
if ( tracer && (tracer.Health > 0) && CheckSight(tracer,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
|
|
{
|
|
Vector3 dirto = level.Vec3Diff(pos,tracer.Vec3Offset(0,0,tracer.height/2));
|
|
double dist = dirto.length();
|
|
if ( dist > 4 )
|
|
{
|
|
dirto /= dist;
|
|
dir = (dir+.02*dirto*(clamp(1.-(dist/500.),0.,1.)**3.)).unit();
|
|
}
|
|
}
|
|
vel = magvel*dir;
|
|
angle = atan2(dir.y,dir.x);
|
|
pitch = asin(-dir.z);
|
|
if ( deto > 1 )
|
|
{
|
|
ExplodeMissile();
|
|
return;
|
|
}
|
|
// proximity check
|
|
let bt = BlockThingsIterator.Create(self,200);
|
|
while ( bt.Next() )
|
|
{
|
|
let t = bt.Thing;
|
|
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),16) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
deto++;
|
|
break;
|
|
}
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
A_StopSound(CHAN_VOICE);
|
|
Super.OnDestroy();
|
|
}
|
|
void A_SparkExplode()
|
|
{
|
|
A_StopSound(CHAN_VOICE);
|
|
A_AlertMonsters(5000);
|
|
SWWMHandler.DoExplosion(self,50,120000,150,80);
|
|
A_QuakeEx(6,6,6,16,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.8);
|
|
A_StartSound("biospark/hit",CHAN_ITEM,attenuation:.8);
|
|
A_StartSound("biospark/hit",CHAN_WEAPON,attenuation:.6);
|
|
A_SprayDecal("ShockMark",172);
|
|
Scale *= FRandom[ExploS](0.8,1.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](16,32);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](3,12);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,4);
|
|
s.scale *= 2.8;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[ExploS](10,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArc",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,20);
|
|
}
|
|
Spawn("BiosparkExplLight",pos);
|
|
}
|
|
void A_SparkSubExpl()
|
|
{
|
|
special1++;
|
|
if ( special1 > 30 ) return;
|
|
double factor = (30-special1)/30.;
|
|
double invfct = 1.-factor;
|
|
SWWMHandler.DoExplosion(self,30*factor,0.,150*invfct);
|
|
SWWMHandler.DoExplosion(self,0,-5000*factor,300*invfct);
|
|
int numpt = int(Random[ExploS](16,32)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8)*factor;
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,5,2)*int(Random[ExploS](40,50)*factor));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 4.*factor;
|
|
s.alpha *= factor;
|
|
s.bAMBUSH = true;
|
|
}
|
|
numpt = int(Random[ExploS](4,8));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = (FRandom[ExploS](5,10)+60*invfct);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.03,.08);
|
|
s.scale *= FRandom[ExploS](.8,1.2)*factor;
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
if ( special1%2 ) return;
|
|
numpt = int(Random[ExploS](0,5)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArc",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,int(10*factor));
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BSPK ABCDEFGHIJ 1 Bright A_SparkTick();
|
|
Loop;
|
|
Death:
|
|
TNT1 A 0 A_SparkExplode();
|
|
XEX2 ABCDEFGHIJKLMNOPQRS 1 Bright A_SparkSubExpl();
|
|
TNT1 A 1
|
|
{
|
|
A_SparkSubExpl();
|
|
A_FadeOut(.05);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkTracer : LineTracer
|
|
{
|
|
Actor ignoreme;
|
|
Array<HitListEntry> hitlist;
|
|
Array<Line> ShootThroughList;
|
|
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
if ( Results.HitType == TRACE_HitActor )
|
|
{
|
|
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
|
if ( Results.HitActor.bSHOOTABLE || (Results.HitActor is 'BiosparkHitbox') )
|
|
{
|
|
let ent = new("HitListEntry");
|
|
ent.hitactor = Results.HitActor;
|
|
ent.hitlocation = Results.HitPos;
|
|
ent.x = Results.HitVector;
|
|
hitlist.Push(ent);
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
|
{
|
|
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
|
return TRACE_Stop;
|
|
ShootThroughList.Push(Results.HitLine);
|
|
return TRACE_Skip;
|
|
}
|
|
return TRACE_Stop;
|
|
}
|
|
}
|
|
|
|
Class BiosparkBeamImpact : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
DamageType "Electric";
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0;
|
|
+FOILINVUL;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_AlertMonsters(2000);
|
|
SWWMHandler.DoExplosion(self,30,120000,100,40);
|
|
A_QuakeEx(3,3,3,12,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.4);
|
|
A_StartSound("biospark/beamhit",CHAN_ITEM,attenuation:1.1);
|
|
A_StartSound("biospark/beamhit",CHAN_WEAPON,attenuation:.8);
|
|
A_SprayDecal("ShockMark",-172);
|
|
Scale *= FRandom[ExploS](0.8,1.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](8,16);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](3,12);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,4);
|
|
s.scale *= 2.;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[ExploS](5,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArcSmall",pos);
|
|
s.target = target;
|
|
s.master = self;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,20);
|
|
}
|
|
Spawn("BiosparkExplLight",pos);
|
|
}
|
|
void A_SparkSubExpl()
|
|
{
|
|
special1++;
|
|
if ( special1 > 30 ) return;
|
|
double factor = (30-special1)/30.;
|
|
double invfct = 1.-factor;
|
|
SWWMHandler.DoExplosion(self,10*factor,0.,50*invfct);
|
|
SWWMHandler.DoExplosion(self,0.,-5000*factor,100*invfct);
|
|
int numpt = int(Random[ExploS](8,16)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8)*factor;
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,5,2)*int(Random[ExploS](40,50)*factor));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 4.*factor;
|
|
s.alpha *= factor;
|
|
s.bAMBUSH = true;
|
|
}
|
|
numpt = int(Random[ExploS](2,4));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = (FRandom[ExploS](5,10)+60*invfct);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.03,.08);
|
|
s.scale *= FRandom[ExploS](.8,1.2)*factor;
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
if ( special1%2 ) return;
|
|
numpt = int(Random[ExploS](0,5)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArcSmall",pos);
|
|
s.target = target;
|
|
s.master = self;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,int(10*factor));
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX2 ABCDEFGHIJKLMNPQRS 1 Bright A_SparkSubExpl();
|
|
TNT1 A 1
|
|
{
|
|
A_SparkSubExpl();
|
|
A_FadeOut(.05);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkComboImpactSub : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
DamageType "Electric";
|
|
RenderStyle "Add";
|
|
Scale 1.4;
|
|
Alpha .4;
|
|
Radius .1;
|
|
Height 0;
|
|
+FOILINVUL;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+FORCEXYBILLBOARD;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
if ( !bAMBUSH ) return;
|
|
SWWMHandler.DoExplosion(self,200,10000,300,120);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX2 ABCDEFGHIJKLMNOPQRS 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BiosparkComboImpact : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
DamageType "Electric";
|
|
RenderStyle "Add";
|
|
Scale 2.;
|
|
Radius .1;
|
|
Height 0;
|
|
+FOILINVUL;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+FORCEXYBILLBOARD;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
void FlashPlayer( int str, double rad )
|
|
{
|
|
double vfov = CVar.GetCVar('fov',players[consoleplayer]).GetFloat()*0.5;
|
|
double hfov = atan(Screen.GetAspectRatio()*tan(vfov));
|
|
let mo = players[consoleplayer].camera;
|
|
Vector3 pp;
|
|
if ( !CheckSight(mo,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) return;
|
|
if ( mo is 'PlayerPawn' ) pp = mo.Vec2OffsetZ(0,0,PlayerPawn(mo).player.viewz);
|
|
else pp = mo.Vec3Offset(0,0,mo.CameraHeight);
|
|
Vector3 sc = level.SphericalCoords(pp,pos,(mo.angle,mo.pitch));
|
|
if ( (abs(sc.x) < hfov) && (abs(sc.y) < vfov) && (sc.z < rad) )
|
|
{
|
|
str = min(int(str*(1.-(sc.z/rad))),255);
|
|
SWWMHandler.DoFlash(mo,Color(str,248,255,240),10);
|
|
SWWMHandler.DoFlash(mo,Color(str,248,255,240),20);
|
|
SWWMHandler.DoFlash(mo,Color(str/2,192,255,160),30);
|
|
SWWMHandler.DoFlash(mo,Color(str/2,192,255,160),50);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_AlertMonsters(6000);
|
|
SWWMHandler.DoExplosion(self,bAMBUSH?(1600+Args[0]*100):1500,480000,bAMBUSH?1200:700,bAMBUSH?900:400);
|
|
A_QuakeEx(9,9,9,25,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:600,rollIntensity:1.5);
|
|
A_StartSound("biospark/bighit",CHAN_ITEM,attenuation:.4);
|
|
A_StartSound("biospark/bighit",CHAN_WEAPON,attenuation:.3);
|
|
A_SprayDecal("BigShockMark",172);
|
|
Scale *= FRandom[ExploS](0.8,1.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](16,32);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](3,24);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](2,5);
|
|
s.scale *= 3.;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[ExploS](10,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,48);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](6,8);
|
|
if ( bAMBUSH ) numpt -= Args[0]/2;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArcBig",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,10);
|
|
if ( bAMBUSH ) s.ReactionTime += 4+Args[0]*4;
|
|
}
|
|
if ( bAMBUSH )
|
|
{
|
|
for ( int i=0; i<(Args[0]/2); i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkBeam",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
}
|
|
}
|
|
Spawn("BiosparkExplLight2",pos);
|
|
FlashPlayer(600,3000);
|
|
}
|
|
void A_SparkSubExpl()
|
|
{
|
|
double mx = bAMBUSH?30.:20.;
|
|
special1++;
|
|
if ( special1 > mx ) return;
|
|
double factor = (mx-special1)/mx;
|
|
double invfct = 1.-factor;
|
|
if ( bAMBUSH )
|
|
{
|
|
factor *= 1.5;
|
|
invfct *= 1.5;
|
|
}
|
|
SWWMHandler.DoExplosion(self,(1500+Args[0]*50)*factor,0.,600*invfct);
|
|
SWWMHandler.DoExplosion(self,0.,-10000*factor,800*invfct);
|
|
int numpt = int(Random[ExploS](8,16)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,16)*factor;
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,5,2)*int(Random[ExploS](40,50)*factor));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 4.*factor;
|
|
s.alpha *= factor;
|
|
s.bAMBUSH = true;
|
|
}
|
|
numpt = int(Random[ExploS](4,8));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = (FRandom[ExploS](5,20)+100*invfct);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.03,.08);
|
|
s.scale *= FRandom[ExploS](.8,1.2)*factor;
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
if ( special1%2 ) return;
|
|
numpt = Random[ExploS](2,5);
|
|
if ( bAMBUSH ) numpt -= 2;
|
|
numpt = int(numpt*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn(bAMBUSH?"BiosparkArcBig":"BiosparkArc",pos);
|
|
s.target = target;
|
|
s.master = self;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,int(10*factor));
|
|
if ( bAMBUSH ) s.ReactionTime += 2+Args[0]*2;
|
|
}
|
|
}
|
|
void A_SparkSubExpl2()
|
|
{
|
|
special2++;
|
|
if ( (special2 > 30) || !(special2%2) ) return;
|
|
int numpt = Random[Sparkster](0,30-special2);
|
|
double ang, pt;
|
|
double mul = bAMBUSH?8:4;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
ang = FRandom[Sparkster](0,360);
|
|
pt = FRandom[Sparkster](-90,90);
|
|
FLineTraceData d;
|
|
Vector3 HitNormal;
|
|
LineTrace(ang,FRandom[Sparkster](10,20)+mul*special2,pt,TRF_THRUACTORS,data:d);
|
|
hitnormal = -d.HitDir;
|
|
if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
|
|
else hitnormal = d.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
|
|
else hitnormal = d.HitSector.ceilingplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
|
if ( !d.LineSide ) hitnormal *= -1;
|
|
}
|
|
let p = Spawn("BiosparkComboImpactSub",d.HitLocation+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = target;
|
|
p.scale *= 2-special2*.02;
|
|
p.alpha *= 1-special2*.02;
|
|
p.bAMBUSH = bAMBUSH;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX2 ABCDEFGHIJKLMNOPQRS 1 Bright
|
|
{
|
|
A_SparkSubExpl();
|
|
A_SparkSubExpl2();
|
|
}
|
|
TNT1 A 1
|
|
{
|
|
A_SparkSubExpl();
|
|
A_SparkSubExpl2();
|
|
A_FadeOut(.05);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkBeam : Actor
|
|
{
|
|
Vector3 nextpos, nextdir;
|
|
|
|
action void A_Trace()
|
|
{
|
|
let t = new("BiosparkTracer");
|
|
t.hitlist.Clear();
|
|
t.ignoreme = target;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
t.ShootThroughList.Clear();
|
|
t.Trace(pos,CurSector,x,speed,TRACE_HitSky);
|
|
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
|
{
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_PCross);
|
|
if ( t.ShootThroughList[i].special == GlassBreak ) // fuck glass
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_Impact);
|
|
}
|
|
for ( int i=0; i<t.hitlist.Size(); i++ )
|
|
{
|
|
if ( (t.hitlist[i].hitactor is 'BiosparkHitbox') && t.hitlist[i].hitactor.target )
|
|
{
|
|
let s = Spawn("BiosparkComboImpact",t.hitlist[i].hitactor.pos);
|
|
s.target = target;
|
|
s.angle = atan2(t.hitlist[i].x.y,t.hitlist[i].x.x);
|
|
s.pitch = asin(-t.hitlist[i].x.z);
|
|
if ( (t.hitlist[i].hitactor is 'BigBiosparkHitbox') )
|
|
{
|
|
s.bAMBUSH = true;
|
|
s.Args[0] = t.hitlist[i].hitactor.target.special1;
|
|
}
|
|
t.hitlist[i].hitactor.target.Destroy();
|
|
}
|
|
else
|
|
{
|
|
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,15000);
|
|
t.hitlist[i].hitactor.DamageMobj(self,target,GetMissileDamage(0,0),'Electric',DMG_THRUSTLESS);
|
|
}
|
|
}
|
|
Vector3 normal = -t.Results.HitVector, dir = t.Results.HitVector;
|
|
if ( t.Results.HitType == TRACE_HitWall )
|
|
{
|
|
normal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
|
|
if ( !t.Results.Side ) normal *= -1;
|
|
t.Results.HitLine.RemoteActivate(target,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( t.Results.ffloor ) normal = -t.Results.ffloor.top.Normal;
|
|
else normal = t.Results.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( t.Results.ffloor ) normal = -t.Results.ffloor.bottom.Normal;
|
|
else normal = t.Results.HitSector.ceilingplane.Normal;
|
|
}
|
|
else
|
|
{
|
|
t.Results.HitPos = level.Vec3Offset(pos,x*speed);
|
|
normal *= 0;
|
|
}
|
|
invoker.nextpos = level.Vec3Offset(t.Results.HitPos,normal*8.);
|
|
if ( t.Results.HitType == TRACE_HasHitSky )
|
|
{
|
|
bAMBUSH = true;
|
|
return;
|
|
}
|
|
if ( t.Results.HitType != TRACE_HitNone )
|
|
{
|
|
let s = Spawn("BiosparkBeamImpact",invoker.nextpos);
|
|
s.target = target;
|
|
s.angle = atan2(normal.y,normal.x);
|
|
s.pitch = asin(-normal.z);
|
|
bAMBUSH = true;
|
|
return;
|
|
}
|
|
double closest = double.infinity;
|
|
let bt = BlockThingsIterator.Create(self,2000);
|
|
while ( bt.Next() )
|
|
{
|
|
let t = bt.Thing;
|
|
double dist;
|
|
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3D(t)) > 2000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
Vector3 dirto = level.Vec3Diff(invoker.nextpos,t.Vec3Offset(0,0,t.height/2));
|
|
if ( dir dot dirto < .2 ) continue;
|
|
if ( dist > closest ) continue;
|
|
closest = dist;
|
|
tracer = t;
|
|
}
|
|
if ( tracer )
|
|
{
|
|
Vector3 dirto = level.Vec3Diff(invoker.nextpos,tracer.Vec3Offset(0,0,tracer.height/2));
|
|
double dist = dirto.length();
|
|
if ( dist > 10 )
|
|
{
|
|
dirto /= dist;
|
|
dir = (dir+.1*dirto*(clamp(1.-(dist/2000.),0.,1.)**4.)).unit();
|
|
}
|
|
}
|
|
invoker.nextdir = dir;
|
|
}
|
|
|
|
action void A_Spread()
|
|
{
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
let c = Spawn("BiosparkChildBeam",pos);
|
|
c.angle = angle;
|
|
c.pitch = pitch;
|
|
if ( frame ) c.SetStateLabel("TrailSpawn");
|
|
c.roll = i*120;
|
|
}
|
|
Vector3 tdir = level.Vec3Diff(pos,invoker.nextpos);
|
|
int numpt = Random[Sparkster](-1,6);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let a = Spawn("BiosparkArc",level.Vec3Offset(pos,tdir*FRandom[Sparkster](0,1)));
|
|
a.angle = angle;
|
|
a.pitch = pitch;
|
|
a.target = target;
|
|
a.ReactionTime += Random[Sparkster](0,20);
|
|
}
|
|
numpt = Random[Sparkster](3,6);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let a = Spawn("BiosparkArcSmall",level.Vec3Offset(pos,tdir*FRandom[Sparkster](0,1)));
|
|
a.angle = angle;
|
|
a.pitch = pitch;
|
|
a.target = target;
|
|
a.master = self;
|
|
a.ReactionTime += Random[Sparkster](0,10);
|
|
}
|
|
numpt = Random[Sparkster](25,50);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*3;
|
|
let s = Spawn("BiosparkSpark",level.Vec3Offset(pos,tdir*FRandom[ExploS](0,1)+ofs));
|
|
s.vel = ofs*FRandom[ExploS](-.1,.2);
|
|
s.scale *= FRandom[ExploS](.5,.8);
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
if ( bAMBUSH ) return;
|
|
let b = Spawn(GetClass(),invoker.nextpos);
|
|
b.frame = 1;
|
|
b.angle = atan2(invoker.nextdir.y,invoker.nextdir.x);
|
|
b.pitch = asin(-invoker.nextdir.z);
|
|
b.target = target;
|
|
b.special1 = special1+1;
|
|
A_StartSound("biospark/zap",CHAN_WEAPON,0,.5,.7);
|
|
let p = Spawn("SparkBeamLight",level.Vec3Offset(pos,tdir/2));
|
|
}
|
|
|
|
action void A_Fade()
|
|
{
|
|
A_FadeOut(.05);
|
|
let t = new("BiosparkTracer");
|
|
t.hitlist.Clear();
|
|
t.ignoreme = target;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
t.ShootThroughList.Clear();
|
|
t.Trace(pos,CurSector,x,speed,0);
|
|
for ( int i=0; i<t.hitlist.Size(); i++ )
|
|
{
|
|
if ( (t.hitlist[i].hitactor is 'BiosparkHitbox') && t.hitlist[i].hitactor.target )
|
|
{
|
|
let s = Spawn("BiosparkComboImpact",t.hitlist[i].hitactor.pos);
|
|
s.target = target;
|
|
s.angle = atan2(t.hitlist[i].x.y,t.hitlist[i].x.x);
|
|
s.pitch = asin(-t.hitlist[i].x.z);
|
|
t.hitlist[i].hitactor.target.Destroy();
|
|
}
|
|
else
|
|
{
|
|
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,15000);
|
|
t.hitlist[i].hitactor.DamageMobj(self,target,int(GetMissileDamage(0,0)*alpha),'Electric',DMG_THRUSTLESS);
|
|
}
|
|
}
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
RenderStyle "Add";
|
|
DamageFunction 30;
|
|
Speed 256;
|
|
Radius .1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
+NOTELEPORT;
|
|
+FOILINVUL;
|
|
+NOINTERACTION;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 # 1;
|
|
XZW1 # 1 A_Trace();
|
|
XZW1 # 1 A_Spread();
|
|
XZW1 # 1 A_Fade();
|
|
Wait;
|
|
Dummy:
|
|
XZW1 AB -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BiosparkChildBeam : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0;
|
|
Alpha .4;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
+NOTELEPORT;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
A_FadeOut(.02);
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1 Bright NoDelay
|
|
{
|
|
return FindState("StarterDev")+Random[Sparkster](0,11)*2;
|
|
}
|
|
Stop;
|
|
TrailSpawn:
|
|
XZW2 A -1 Bright
|
|
{
|
|
return FindState("TrailerDev")+Random[Sparkster](0,11)*2;
|
|
}
|
|
Stop;
|
|
StarterDev:
|
|
#### # 20 Bright;
|
|
XZW1 B -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 C -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 D -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 E -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 F -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 G -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 H -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 I -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 J -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 K -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 L -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 M -1 Bright;
|
|
Stop;
|
|
TrailerDev:
|
|
#### # 20 Bright;
|
|
XZW2 B -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 C -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 D -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 E -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 F -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 G -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 H -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 I -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 J -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 K -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 L -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW2 M -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BiosparkArc : Actor
|
|
{
|
|
Vector3 nextpos, nextdir;
|
|
|
|
action void A_Trace()
|
|
{
|
|
let t = new("CandyBeamTracer");
|
|
t.hitlist.Clear();
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
t.ShootThroughList.Clear();
|
|
t.Trace(pos,CurSector,x,speed,TRACE_HitSky);
|
|
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
|
{
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_PCross);
|
|
if ( t.ShootThroughList[i].special == GlassBreak ) // fuck glass
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_Impact);
|
|
}
|
|
for ( int i=0; i<t.hitlist.Size(); i++ )
|
|
{
|
|
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,-t.hitlist[i].x,GetMissileDamage(0,0)*1000);
|
|
t.hitlist[i].hitactor.DamageMobj(self,target,GetMissileDamage(0,0),'Electric',DMG_THRUSTLESS);
|
|
}
|
|
Vector3 normal = -t.Results.HitVector, dir = t.Results.HitVector;
|
|
if ( t.Results.HitType == TRACE_HitWall )
|
|
{
|
|
normal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
|
|
if ( !t.Results.Side ) normal *= -1;
|
|
t.Results.HitLine.RemoteActivate(target,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
|
dir -= 2*normal*(dir dot normal);
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( t.Results.ffloor ) normal = -t.Results.ffloor.top.Normal;
|
|
else normal = t.Results.HitSector.floorplane.Normal;
|
|
dir -= 2*normal*(dir dot normal);
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( t.Results.ffloor ) normal = -t.Results.ffloor.bottom.Normal;
|
|
else normal = t.Results.HitSector.ceilingplane.Normal;
|
|
dir -= 2*normal*(dir dot normal);
|
|
}
|
|
else
|
|
{
|
|
t.Results.HitPos = level.Vec3Offset(pos,x*speed);
|
|
normal *= 0;
|
|
}
|
|
invoker.nextpos = level.Vec3Offset(t.Results.HitPos,normal);
|
|
if ( t.Results.HitType == TRACE_HasHitSky )
|
|
{
|
|
bAMBUSH = true;
|
|
return;
|
|
}
|
|
double a = FRandom[Sparkster](0,360), s = FRandom[Sparkster](0.,.8);
|
|
dir = (dir+cos(a)*y*s+sin(a)*z*s).unit();
|
|
if ( master )
|
|
{
|
|
Vector3 dirto = level.Vec3Diff(invoker.nextpos,master.Vec3Offset(0,0,master.height/2));
|
|
double dist = dirto.length();
|
|
if ( dist > 10 )
|
|
{
|
|
dirto /= dist;
|
|
dir = (dir+.5*dirto*(clamp(1.-(dist/3000.),0.,1.)**1.5)).unit();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double closest = double.infinity;
|
|
let bt = BlockThingsIterator.Create(self,1500);
|
|
while ( bt.Next() )
|
|
{
|
|
let t = bt.Thing;
|
|
double dist;
|
|
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3D(t)) > 1500) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
Vector3 dirto = level.Vec3Diff(invoker.nextpos,t.Vec3Offset(0,0,t.height/2));
|
|
if ( dir dot dirto < .2 ) continue;
|
|
if ( dist > closest ) continue;
|
|
closest = dist;
|
|
tracer = t;
|
|
}
|
|
if ( tracer )
|
|
{
|
|
Vector3 dirto = level.Vec3Diff(invoker.nextpos,tracer.Vec3Offset(0,0,tracer.height/2));
|
|
double dist = dirto.length();
|
|
if ( dist > 10 )
|
|
{
|
|
dirto /= dist;
|
|
dir = (dir+.5*dirto*(clamp(1.-(dist/1500.),0.,1.)**2.)).unit();
|
|
}
|
|
}
|
|
}
|
|
invoker.nextdir = dir;
|
|
}
|
|
action void A_Spread( Sound arcsnd = "", double attn = 1., int extra = 0 )
|
|
{
|
|
Vector3 tdir = level.Vec3Diff(pos,invoker.nextpos);
|
|
if ( (extra > 1) && !Random[Sparkster](0,3) )
|
|
{
|
|
for ( int i=0; i<3; i++ )
|
|
{
|
|
let r = Spawn("BiosparkArc",level.Vec3Offset(pos,tdir*FRandom[Sparkster](0,1)));
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
double a = FRandom[Sparkster](0,360), s = FRandom[Sparkster](0.,1.);
|
|
Vector3 sdir = (x+y*cos(a)*s+z*sin(a)*s).unit();
|
|
r.angle = atan2(sdir.y,sdir.x);
|
|
r.pitch = asin(-sdir.z);
|
|
r.target = target;
|
|
r.master = master;
|
|
r.ReactionTime /= 3;
|
|
}
|
|
}
|
|
if ( (special1 > ReactionTime) || bAMBUSH ) return;
|
|
let b = Spawn(GetClass(),invoker.nextpos);
|
|
b.angle = atan2(invoker.nextdir.y,invoker.nextdir.x);
|
|
b.pitch = asin(-invoker.nextdir.z);
|
|
b.target = target;
|
|
b.master = master;
|
|
b.tracer = tracer;
|
|
b.special1 = special1+1;
|
|
b.special2 = special2;
|
|
if ( (arcsnd != "") && !((special1+special2)%3) && !Random[Sparkster](0,3-extra) ) A_StartSound(arcsnd,CHAN_WEAPON,attenuation:attn);
|
|
if ( !((special1+special2)%8) && !Random[Sparkster](0,5-extra) )
|
|
{
|
|
let p = Spawn((extra>1)?"SparkArcLightBig":(extra>0)?"SparkArcLight":"SparkArcLightSmall",level.Vec3Offset(pos,tdir/2));
|
|
p.args[3] = int(speed*8);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
frame = Random[Sparkster](0,11);
|
|
if ( !special1 ) special2 = Random[Sparkster](0,8);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
RenderStyle "Add";
|
|
DamageFunction 5;
|
|
ReactionTime 16;
|
|
Speed 16;
|
|
Radius .1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
+NOTELEPORT;
|
|
+FOILINVUL;
|
|
+NOINTERACTION;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 # 1 Bright;
|
|
XZW1 # 1 Bright A_Trace();
|
|
XZW1 # 1 Bright A_Spread("biospark/bigarc",.6,1);
|
|
XZW1 # 1 Bright A_FadeOut(.05);
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkArcSmall : BiosparkArc
|
|
{
|
|
Default
|
|
{
|
|
ReactionTime 12;
|
|
DamageFunction 1;
|
|
Speed 8;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 # 1 Bright;
|
|
XZW1 # 1 Bright A_Trace();
|
|
XZW1 # 1 Bright A_Spread("biospark/arc",2.,0);
|
|
XZW1 # 1 Bright A_FadeOut(.1);
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkArcBig : BiosparkArc
|
|
{
|
|
Default
|
|
{
|
|
ReactionTime 10;
|
|
DamageFunction 100;
|
|
Speed 64;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 # 1 Bright;
|
|
XZW1 # 1 Bright A_Trace();
|
|
XZW1 # 1 Bright A_Spread("biospark/hugearc",.4,2);
|
|
XZW1 # 1 Bright A_FadeOut(.025);
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkSpark : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale .8;
|
|
Radius .1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SSPK A 1 Bright
|
|
{
|
|
A_SetScale(scale.x*specialf1);
|
|
A_FadeOut(specialf2);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class BiosparkCore : Actor
|
|
{
|
|
Vector3 oldvel;
|
|
double anglevel, pitchvel, rollvel;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_SPARKSTER";
|
|
PROJECTILE;
|
|
BounceType "Hexen";
|
|
+CANBOUNCEWATER;
|
|
+USEBOUNCESTATE;
|
|
+DONTBOUNCEONSKY;
|
|
+NODAMAGETHRUST;
|
|
+NOTELEPORT;
|
|
+INTERPOLATEANGLES;
|
|
+FORCEXYBILLBOARD;
|
|
-NOGRAVITY;
|
|
Speed 30;
|
|
Gravity .1;
|
|
BounceFactor 1.;
|
|
WallBounceFactor 1.;
|
|
Radius 2;
|
|
Height 2;
|
|
ReactionTime 25;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
anglevel = FRandom[Sparkster](-8,8);
|
|
rollvel = FRandom[Sparkster](-8,8);
|
|
pitchvel = FRandom[Sparkster](-8,8);
|
|
}
|
|
override void Tick()
|
|
{
|
|
oldvel = vel;
|
|
Super.Tick();
|
|
}
|
|
void A_HandleBounce()
|
|
{
|
|
bHITOWNER = true;
|
|
Vector3 HitNormal = -vel.unit();
|
|
F3DFloor ff;
|
|
if ( BlockingFloor )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(CurSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
ff = CurSector.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff ) HitNormal = -ff.top.Normal;
|
|
else HitNormal = BlockingFloor.floorplane.Normal;
|
|
}
|
|
else if ( BlockingCeiling )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(CurSector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
ff = CurSector.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff ) HitNormal = -ff.bottom.Normal;
|
|
else HitNormal = BlockingCeiling.ceilingplane.Normal;
|
|
}
|
|
else if ( BlockingLine )
|
|
{
|
|
HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
|
int wside = SWWMUtility.PointOnLineSide(pos.xy,BlockingLine);
|
|
if ( !wside ) HitNormal *= -1;
|
|
}
|
|
else if ( BlockingMobj )
|
|
{
|
|
Vector3 diff = level.Vec3Diff(BlockingMobj.Vec3Offset(0,0,BlockingMobj.Height/2),pos);
|
|
HitNormal = diff.unit();
|
|
}
|
|
// undo the bounce, we need to hook in our own
|
|
vel = oldvel;
|
|
// re-do the bounce with our formula
|
|
vel = (vel dot HitNormal)*HitNormal*FRandom[Spreadgun](-1.8,-1.)+vel;
|
|
vel += (FRandom[Spreadgun](-.4,.4),FRandom[Spreadgun](-.4,.4),FRandom[Spreadgun](-.4,.4));
|
|
vel *= .6;
|
|
anglevel = FRandom[Sparkster](-16,16);
|
|
rollvel = FRandom[Sparkster](-16,16);
|
|
pitchvel = FRandom[Sparkster](-16,16);
|
|
// slam jam
|
|
A_StartSound("hellblazer/bounce",CHAN_VOICE,CHANF_OVERLAP,max(0.,(vel.length()/30.-.2))**.5);
|
|
if ( (vel.length() < 5) && (pos.z <= floorz) )
|
|
{
|
|
ClearBounce();
|
|
ExplodeMissile();
|
|
}
|
|
}
|
|
void A_Deploy()
|
|
{
|
|
A_AlertMonsters(700);
|
|
A_QuakeEx(7,7,7,8,0,1400,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
A_StartSound("biospark/deploy",CHAN_ITEM,attenuation:.7);
|
|
A_StartSound("biospark/deploy",CHAN_WEAPON,attenuation:.5);
|
|
let s = Spawn("BigBiospark",pos);
|
|
s.target = target;
|
|
Vector3 dir = vel.unit();
|
|
s.angle = atan2(dir.y,dir.x);
|
|
s.pitch = asin(-dir.z);
|
|
s.special1 = special1;
|
|
}
|
|
void A_SparkExplode()
|
|
{
|
|
bNOGRAVITY = true;
|
|
A_SetRenderStyle(1.,STYLE_Add);
|
|
A_AlertMonsters(5000);
|
|
SWWMHandler.DoExplosion(self,50,120000,150,60);
|
|
A_QuakeEx(6,6,6,16,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.8);
|
|
Scale *= FRandom[ExploS](0.8,1.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](16,32);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](3,12);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,4);
|
|
s.scale *= 2.8;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[ExploS](10,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArc",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,20);
|
|
}
|
|
Spawn("BiosparkExplLight",pos);
|
|
}
|
|
void A_SparkSubExpl()
|
|
{
|
|
special2++;
|
|
if ( special2 > 30 ) return;
|
|
double factor = (30-special2)/30.;
|
|
double invfct = 1.-factor;
|
|
SWWMHandler.DoExplosion(self,0.,-5000*factor,300*invfct);
|
|
SWWMHandler.DoExplosion(self,30*factor,0.,150*invfct);
|
|
int numpt = int(Random[ExploS](16,32)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8)*factor;
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,5,2)*int(Random[ExploS](40,50)*factor));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 4.*factor;
|
|
s.alpha *= factor;
|
|
s.bAMBUSH = true;
|
|
}
|
|
numpt = int(Random[ExploS](4,8));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = (FRandom[ExploS](5,10)+60*invfct);
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("BiosparkSpark",spos);
|
|
s.vel = ofs*FRandom[ExploS](-.03,.08);
|
|
s.scale *= FRandom[ExploS](.8,1.2)*factor;
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
if ( special2%2 ) return;
|
|
numpt = int(Random[ExploS](0,5)*factor);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("BiosparkArc",pos);
|
|
s.target = target;
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[Sparkster](0,int(10*factor));
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1
|
|
{
|
|
A_CountDown();
|
|
angle += invoker.anglevel;
|
|
pitch += invoker.pitchvel;
|
|
roll += invoker.rollvel;
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.1,.4);
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel+vel*.5;
|
|
s.SetShade(Color(4,5,2)*Random[ExploS](40,50));
|
|
s.A_SetRenderStyle(s.alpha*.4,STYLE_AddShaded);
|
|
s.scale *= 2.;
|
|
s.bAMBUSH = true;
|
|
}
|
|
Wait;
|
|
Bounce:
|
|
XZW1 A 0 A_HandleBounce();
|
|
Goto Spawn;
|
|
Death:
|
|
TNT1 A 0 A_Deploy();
|
|
TNT1 A 0 A_SparkExplode();
|
|
XEX2 ABCDEFGHIJKLMNOPQRS 1 Bright A_SparkSubExpl();
|
|
TNT1 A 1
|
|
{
|
|
A_SparkSubExpl();
|
|
A_FadeOut(.05);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class SparksterMag : SWWMCasing
|
|
{
|
|
Default
|
|
{
|
|
Mass 10;
|
|
BounceFactor 0.4;
|
|
WallBounceFactor 0.4;
|
|
BounceSound "explodium/mag";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
heat = 0;
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
XZW1 BC -1
|
|
{
|
|
pitch = 0;
|
|
angle = FRandom[Junk](0,360);
|
|
roll = 0;
|
|
frame = RandomPick[Junk](1,2);
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class Sparkster : SWWMWeapon
|
|
{
|
|
int clipcount;
|
|
|
|
Property ClipCount : clipcount;
|
|
|
|
transient ui TextureID WeaponBox, AmmoBar[3];
|
|
transient ui Font TewiFont;
|
|
transient ui DynamicValueInterpolator iclip;
|
|
transient int failtime;
|
|
|
|
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
|
|
{
|
|
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
|
|
if ( !WeaponBox )
|
|
{
|
|
WeaponBox = TexMan.CheckForTexture("graphics/HUD/BiosparkDisplay.png",TexMan.Type_Any);
|
|
AmmoBar[0] = TexMan.CheckForTexture("graphics/HUD/BiosparkBar.png",TexMan.Type_Any);
|
|
AmmoBar[1] = TexMan.CheckForTexture("graphics/HUD/BiosparkBarRed.png",TexMan.Type_Any);
|
|
AmmoBar[2] = TexMan.CheckForTexture("graphics/HUD/BiosparkBarGray.png",TexMan.Type_Any);
|
|
}
|
|
Screen.DrawTexture(WeaponBox,false,bx-28,by-28,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-26,by-26,String.Format("%2d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawTexture(AmmoBar[2],false,bx-26,by-8,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
bool blinking = (failtime>gametic)&&((failtime-gametic)%16>=8);
|
|
Screen.DrawTexture(AmmoBar[clipcount<4],false,bx-26,by-8,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,iclip?(iclip.GetValue()/10):0,DTA_ColorOverlay,blinking?Color(128,0,0,0):Color(0,0,0,0));
|
|
}
|
|
|
|
override void HudTick()
|
|
{
|
|
if ( !iclip ) iclip = DynamicValueInterpolator.Create(clipcount*30,.25,1,10);
|
|
else iclip.Update(clipcount*30);
|
|
}
|
|
|
|
override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount )
|
|
{
|
|
if ( sv_infiniteammo || Owner.FindInventory('PowerInfiniteAmmo',true) ) return true;
|
|
if ( (fireMode == PrimaryFire) || (fireMode == AltFire) ) return ((clipcount > 0) || (Ammo1.Amount > 0));
|
|
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
|
|
}
|
|
|
|
override bool ReportHUDAmmo()
|
|
{
|
|
if ( clipcount > 0 ) return true;
|
|
return Super.ReportHUDAmmo();
|
|
}
|
|
|
|
action void A_FireSpark( int mode )
|
|
{
|
|
int scnt = invoker.clipcount;
|
|
if ( mode == 2 ) invoker.clipcount = 0;
|
|
else invoker.clipcount = max(0,invoker.clipcount-1);
|
|
Vector3 x, y, z, x2, y2, z2, dir;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+5*y-5*z);
|
|
double a, s;
|
|
Actor p;
|
|
switch ( mode )
|
|
{
|
|
case 0:
|
|
// spark
|
|
A_StartSound("biospark/fire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.7);
|
|
A_QuakeEx(2,2,2,5,0,8,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.2);
|
|
A_ZoomFactor(.96,ZOOM_INSTANT);
|
|
A_ZoomFactor(1.);
|
|
A_SWWMFlash();
|
|
SWWMHandler.DoFlash(self,Color(64,192,255,96),3);
|
|
A_AlertMonsters(5000);
|
|
A_PlayerFire();
|
|
a = FRandom[Spread](0,360);
|
|
s = FRandom[Spread](0,.007);
|
|
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
|
p = Spawn("BiosparkBall",origin);
|
|
p.target = self;
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = asin(-dir.z);
|
|
p.vel = dir*p.speed;
|
|
break;
|
|
case 1:
|
|
// beam
|
|
A_StartSound("biospark/altfire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.8);
|
|
A_QuakeEx(3,3,3,5,0,8,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.3);
|
|
A_ZoomFactor(.95,ZOOM_INSTANT);
|
|
A_ZoomFactor(1.);
|
|
A_SWWMFlash();
|
|
SWWMHandler.DoFlash(self,Color(64,192,255,96),3);
|
|
A_AlertMonsters(4000);
|
|
A_PlayerFire();
|
|
a = FRandom[Spread](0,360);
|
|
s = FRandom[Spread](0,.003);
|
|
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
|
p = Spawn("BiosparkBeam",origin);
|
|
p.target = self;
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = asin(-dir.z);
|
|
p.frame = 0;
|
|
break;
|
|
case 2:
|
|
// big spark
|
|
A_StartSound("biospark/thirdfire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:1.5);
|
|
A_QuakeEx(5,5,5,10,0,8,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.6);
|
|
A_ZoomFactor(.94,ZOOM_INSTANT);
|
|
A_ZoomFactor(1.);
|
|
A_AlertMonsters(1200);
|
|
A_PlayerFire();
|
|
SWWMHandler.DoKnockback(self,-x,2500.);
|
|
a = FRandom[Spread](0,360);
|
|
s = FRandom[Spread](0,.012);
|
|
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
|
p = Spawn("BiosparkCore",origin);
|
|
p.target = self;
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = asin(-dir.z);
|
|
p.vel = dir*p.speed;
|
|
p.vel.z += 3.5;
|
|
p.special1 = scnt;
|
|
break;
|
|
}
|
|
}
|
|
|
|
action void A_DropMag()
|
|
{
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-2*y-10*z);
|
|
let c = Spawn("SparksterMag",origin);
|
|
c.angle = angle;
|
|
c.pitch = pitch;
|
|
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](-1.2,.3)-(0,0,FRandom[Junk](2,3));
|
|
c.vel += vel*.5;
|
|
}
|
|
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( Owner.player && (Owner.player.Readyweapon == self) )
|
|
Owner.A_StartSound("biospark/idle",CHAN_WEAPONEXTRA,CHANF_LOOPING,.4,4.);
|
|
}
|
|
|
|
action void A_FailZoom()
|
|
{
|
|
invoker.failtime = gametic+48;
|
|
A_StartSound("biospark/fail",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_SPARKSTER";
|
|
Inventory.PickupMessage "$I_SPARKSTER";
|
|
Obituary "$O_SPARKSTER";
|
|
Inventory.Icon "graphics/HUD/Icons/W_Sparkster.png";
|
|
Weapon.SlotNumber 7;
|
|
Weapon.UpSound "biospark/select";
|
|
Weapon.SelectionOrder 600;
|
|
Stamina 200000;
|
|
Weapon.AmmoType1 "SparkUnit";
|
|
Weapon.AmmoGive1 1;
|
|
Sparkster.ClipCount 8;
|
|
+SWWMWEAPON.NOFIRSTGIVE;
|
|
+WEAPON.EXPLOSIVE;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
Select:
|
|
XZW2 G 2
|
|
{
|
|
A_FullRaise();
|
|
A_StartSound("biospark/idle",CHAN_WEAPONEXTRA,CHANF_LOOPING,.4,4.);
|
|
}
|
|
XZW2 HIJKLM 2;
|
|
Goto Ready;
|
|
Deselect:
|
|
XZW2 A 2 A_StartSound("biospark/deselect",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW2 BCDEFG 2;
|
|
XZW2 G -1
|
|
{
|
|
A_StopSound(CHAN_WEAPONEXTRA);
|
|
A_FullLower();
|
|
}
|
|
Stop;
|
|
Ready:
|
|
XZW2 A 1
|
|
{
|
|
A_WeaponReady(WRF_ALLOWZOOM|WRF_ALLOWUSER1|WRF_ALLOWRELOAD);
|
|
if ( player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK|BT_ZOOM) )
|
|
invoker.CheckAmmo(EitherFire,true);
|
|
}
|
|
Wait;
|
|
Fire:
|
|
XZW2 A 0 A_JumpIf(invoker.ClipCount<=0,"Reload");
|
|
XZW2 A 1 A_StartSound("biospark/prefire",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW4 Y 12;
|
|
XZW4 Y 1 A_FireSpark(0);
|
|
XZW2 NOPQ 2;
|
|
XZW2 A 0 A_JumpIf(!(player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK))||(invoker.ClipCount<=0),"Vent");
|
|
Goto Ready;
|
|
AltFire:
|
|
XZW2 A 0 A_JumpIf(invoker.ClipCount<=0,"Reload");
|
|
XZW2 A 1 A_StartSound("biospark/prefire",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW4 Z 12;
|
|
XZW4 Z 1 A_FireSpark(1);
|
|
XZW2 RSTU 2;
|
|
XZW2 A 0 A_JumpIf(!(player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK))||(invoker.ClipCount<=0),"Vent");
|
|
Goto Ready;
|
|
Vent:
|
|
XZW2 A 12
|
|
{
|
|
A_Overlay(PSP_WEAPON+2,"VentFlash");
|
|
A_OverlayFlags(PSP_WEAPON+2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
|
|
A_OverlayRenderStyle(PSP_WEAPON+2,STYLE_Add);
|
|
A_StartSound("biospark/hiss",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
Goto Ready;
|
|
VentFlash:
|
|
XZWY ABCDEFGHIJKLMNOPQRSTUVWX 1;
|
|
Stop;
|
|
Zoom:
|
|
XZW2 A 0 A_JumpIf(invoker.ClipCount<=0,"Reload");
|
|
XZW2 A 0 A_JumpIf(invoker.ClipCount<4,"NoZoom");
|
|
XZW2 A 1 A_StartSound("biospark/prethird",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW5 A 12;
|
|
XZW5 A 1 A_FireSpark(2);
|
|
XZW2 VWXYZ 2;
|
|
Goto Ready;
|
|
NoZoom:
|
|
XZW2 A 1 A_StartSound("biospark/prethird",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW5 A 12;
|
|
XZW5 A 8 A_FailZoom();
|
|
XZW2 A 20;
|
|
Goto Ready;
|
|
Reload:
|
|
XZW2 A 0 A_JumpIf((invoker.clipcount>0)||((invoker.Ammo1.Amount<=0)&&!sv_infiniteammo&&!FindInventory('PowerInfiniteAmmo',true)),"Idle");
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("biospark/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerReload();
|
|
}
|
|
XZW3 ABCDE 2;
|
|
XZW3 F 2
|
|
{
|
|
invoker.clipcount = 0;
|
|
A_StartSound("biospark/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZW3 GHIJKL 2;
|
|
XZW3 M 2 A_DropMag();
|
|
XZW3 NOPQR 2;
|
|
XZW3 S 2
|
|
{
|
|
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
|
invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1);
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
A_StartSound("biospark/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZW3 UVW 2;
|
|
XZW3 X 2 A_StartSound("biospark/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW3 YZ 2;
|
|
XZW4 ABCD 2;
|
|
Goto Vent;
|
|
Idle:
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("biospark/checkout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerCheckGun();
|
|
}
|
|
XZW5 BCDE 2;
|
|
XZW5 FGHI 3;
|
|
XZW5 JKLM 2;
|
|
XZW5 NOPQ 3;
|
|
XZW5 RST 2;
|
|
XZW5 UVXY 3;
|
|
Goto Ready;
|
|
User1:
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_StartSound("biospark/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerMelee();
|
|
}
|
|
XZW4 EFG 2;
|
|
XZW4 H 1 A_Parry(9);
|
|
XZW4 IJ 1;
|
|
XZW4 K 2 A_Melee(60,"demolitionist/whitm");
|
|
XZW4 LMNOPQ 2;
|
|
XZW4 R 2 A_StartSound("biospark/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW4 STUVWX 2;
|
|
Goto Ready;
|
|
Flash:
|
|
XZWZ A 2 Bright
|
|
{
|
|
let l = Spawn("SWWMWeaponLight",pos);
|
|
l.args[0] = 192;
|
|
l.args[1] = 255;
|
|
l.args[2] = 96;
|
|
l.target = self;
|
|
}
|
|
Stop;
|
|
}
|
|
}
|