2085 lines
54 KiB
Text
2085 lines
54 KiB
Text
// Imanaki Corp Hellfire Cannon Mk3, aka "Hellblazer" (from SWWM series, originally inspired by the Hellraiser from OMGWEAPONS)
|
|
// Slot 6, replaces Rocket Launcher, Phoenix Rod, Firestorm
|
|
|
|
Class HellblazerExplLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "HellExpl";
|
|
Args 0,0,0,200;
|
|
ReactionTime 25;
|
|
}
|
|
}
|
|
Class HellblazerExplLight2 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "HellExpl";
|
|
Args 0,0,0,120;
|
|
ReactionTime 20;
|
|
}
|
|
}
|
|
Class HellblazerExplLight3 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "HellExpl";
|
|
Args 0,0,0,900;
|
|
ReactionTime 60;
|
|
}
|
|
}
|
|
|
|
Class HellblazerSubExpl : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 2.2;
|
|
Alpha .4;
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
HEXP ABCDEFGHIJKLMNOPQR 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerRing : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 2.;
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG3 ACEGIKMOQSUW 1 Bright A_SetScale(scale.x*1.15);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerRing2 : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 3.;
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XRG3 ABCDEFGHIJKLMNOPQRSTUVWX 1 Bright A_SetScale(scale.x*1.1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
Scale .2;
|
|
Alpha .3;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
SetState(FindState("Spawn")+Random[ExploS](0,7));
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
JFLR ABCDEFGH 1 Bright
|
|
{
|
|
A_FadeOut(.06);
|
|
A_SetScale(scale.x*.95);
|
|
if ( waterlevel > 0 )
|
|
{
|
|
let b = Spawn("SWWMBubble",pos);
|
|
b.vel = vel;
|
|
b.scale *= scale.x;
|
|
Destroy();
|
|
}
|
|
}
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerFlare : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
if ( !master ) return;
|
|
State sp = FindState("Spawn");
|
|
if ( master is 'HellblazerCrackshot' ) SetState(sp+1);
|
|
else if ( master is 'HellblazerRavager' ) SetState(sp+2);
|
|
else if ( master is 'HellblazerWarhead' ) SetState(sp+3);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !master || !master.bMISSILE )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
Vector3 traildir = -(cos(master.angle)*cos(master.pitch),sin(master.angle)*cos(master.pitch),sin(-master.pitch));
|
|
SetOrigin(level.Vec3Offset(master.pos,traildir*3),true);
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
HFLR ABCD -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// rockets
|
|
Class HellblazerMissile : Actor
|
|
{
|
|
int deto;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_HELLBLAZER";
|
|
DamageType 'Exploded';
|
|
Radius 4;
|
|
Height 8;
|
|
Speed 50;
|
|
PROJECTILE;
|
|
+EXPLODEONWATER;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
if ( bNOGRAVITY )
|
|
{
|
|
A_StartSound("hellblazer/fly",CHAN_BODY,CHANF_LOOP,1.,2.);
|
|
let t = Spawn("HellblazerFlare",pos);
|
|
t.master = self;
|
|
}
|
|
}
|
|
|
|
void A_BlazerTick( Color smokecol )
|
|
{
|
|
Vector3 traildir = -(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch));
|
|
for ( int i=0; i<3; i++ )
|
|
{
|
|
let s = Spawn("SWWMHalfSmoke",level.Vec3Offset(pos,traildir*3));
|
|
s.SetShade(smokecol*Random[Hellblazer](48,63));
|
|
s.scale *= FRandom[Hellblazer](.8,1.2);
|
|
s.special1 = Random[Hellblazer](0,2);
|
|
s.alpha *= .5;
|
|
s.vel = .3*vel + (traildir+(FRandom[Hellblazer](-.4,.4),FRandom[Hellblazer](-.4,.4),FRandom[Hellblazer](-.4,.4))).unit()*FRandom[Hellblazer](1.,2.);
|
|
}
|
|
if ( bNOGRAVITY )
|
|
{
|
|
for ( double i=0.; i<vel.length(); i+= 5. )
|
|
{
|
|
let t = Spawn("HellblazerTrail",level.Vec3Offset(pos,-vel.unit()*i+traildir*3));
|
|
t.vel = traildir*4.;
|
|
}
|
|
}
|
|
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.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),bNOGRAVITY?50:90) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
deto++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void A_BlazerMissileExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
bRollSprite = false;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("BigRocketBlast",50);
|
|
A_SetScale(4.5);
|
|
SWWMUtility.DoExplosion(self,350,320000,200,90);
|
|
A_NoGravity();
|
|
A_QuakeEx(5,5,5,15,0,1500,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollIntensity:.8);
|
|
A_StopSound(CHAN_BODY);
|
|
A_StartSound("hellblazer/hitm",CHAN_WEAPON,attenuation:.8);
|
|
A_StartSound("hellblazer/hitm",CHAN_VOICE,attenuation:.5);
|
|
A_AlertMonsters(swwm_uncapalert?0:2500);
|
|
Spawn("HellblazerExplLight",pos);
|
|
int numpt = Random[Hellblazer](12,24);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](2,8);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,3,2)*Random[Hellblazer](48,63));
|
|
s.special1 = Random[Hellblazer](1,4);
|
|
s.scale *= 2.8;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[Hellblazer](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](4,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Hellblazer](12,16);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](10,20);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
|
}
|
|
Spawn("HellblazerRing",pos);
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,350,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
|
}
|
|
|
|
void A_SubExpl( double xscale = 1. )
|
|
{
|
|
special1++;
|
|
if ( (special1 > 8) || !(special1%2) ) return;
|
|
int numpt = Random[Hellblazer](0,8-special1);
|
|
double ang, pt;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
ang = FRandom[Hellblazer](0,360);
|
|
pt = FRandom[Hellblazer](-90,90);
|
|
FLineTraceData d;
|
|
Vector3 HitNormal;
|
|
LineTrace(ang,FRandom[Hellblazer](10,20)+10*special1*xscale,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("HellblazerSubExpl",d.HitLocation+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = target;
|
|
p.scale *= xscale*(2-special1*.1);
|
|
p.alpha *= 1-special1*.1;
|
|
}
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1 A_BlazerTick(Color(4,3,2));
|
|
Wait;
|
|
Death:
|
|
TNT1 A 0 A_BlazerMissileExplode();
|
|
HEXP ABCDEFGHIJKLMNOPQR 1 Bright A_SubExpl();
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerCrackshot : HellblazerMissile
|
|
{
|
|
void A_BlazerCrackshotExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
bRollSprite = false;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("BigRocketBlast",50);
|
|
A_SetScale(6.);
|
|
SWWMUtility.DoExplosion(self,300,320000,250,100);
|
|
A_NoGravity();
|
|
A_QuakeEx(6,6,6,20,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.);
|
|
A_StopSound(CHAN_BODY);
|
|
A_StartSound("hellblazer/hitc",CHAN_WEAPON,attenuation:.7);
|
|
A_StartSound("hellblazer/hitc",CHAN_VOICE,attenuation:.4);
|
|
A_AlertMonsters(swwm_uncapalert?0:3000);
|
|
Spawn("HellblazerExplLight",pos);
|
|
int numpt = Random[Hellblazer](12,24);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](2,8);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(2,4,2)*Random[Hellblazer](48,63));
|
|
s.special1 = Random[Hellblazer](1,4);
|
|
s.scale *= 2.8;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[Hellblazer](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](4,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Hellblazer](12,16);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](10,20);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
|
}
|
|
Spawn("HellblazerRing",pos);
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
double ang = FRandom[Hellblazer](0,360);
|
|
double pt = FRandom[Hellblazer](-90,90);
|
|
let c = Spawn("HellblazerClusterMini",pos);
|
|
c.angle = ang;
|
|
c.pitch = pt;
|
|
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),sin(-pt))*c.speed*FRandom[Hellblazer](.8,1.2);
|
|
c.target = target;
|
|
c.ReactionTime += Random[Hellblazer](-10,10);
|
|
}
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,300,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1 A_BlazerTick(Color(2,4,2));
|
|
Wait;
|
|
Death:
|
|
TNT1 A 0 A_BlazerCrackshotExplode();
|
|
HEXP ABCDEFGHIJKLMNOPQR 1 Bright A_SubExpl(1.25);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerRavager : HellblazerMissile
|
|
{
|
|
void A_BlazerRavagerExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
bRollSprite = false;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("HugeRocketBlast",50);
|
|
A_SetScale(8.);
|
|
SWWMUtility.DoExplosion(self,400,320000,300,120);
|
|
A_NoGravity();
|
|
A_QuakeEx(6,6,6,30,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.);
|
|
A_StopSound(CHAN_BODY);
|
|
A_StartSound("hellblazer/hitr",CHAN_WEAPON,attenuation:.6);
|
|
A_StartSound("hellblazer/hitr",CHAN_VOICE,attenuation:.3);
|
|
A_AlertMonsters(swwm_uncapalert?0:4500);
|
|
Spawn("HellblazerExplLight",pos);
|
|
int numpt = Random[Hellblazer](16,28);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](4,12);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(4,2,2)*Random[Hellblazer](48,63));
|
|
s.special1 = Random[Hellblazer](2,5);
|
|
s.scale *= 3.2;
|
|
s.alpha *= .3;
|
|
}
|
|
numpt = Random[Hellblazer](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](4,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Hellblazer](12,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](10,20);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
|
}
|
|
Spawn("HellblazerRing",pos);
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,400,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
|
}
|
|
|
|
void A_RavagerSub()
|
|
{
|
|
special2++;
|
|
if ( (special2 > 10) || (special2%3) ) return;
|
|
int numpt = 6-special2/2;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[Hellblazer](0,360);
|
|
double pt = FRandom[Hellblazer](-90,90);
|
|
let c = Spawn("HellblazerRavagerArm",pos);
|
|
c.angle = ang;
|
|
c.pitch = pt;
|
|
c.target = target;
|
|
}
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1 A_BlazerTick(Color(4,2,2));
|
|
Wait;
|
|
Death:
|
|
TNT1 A 0 A_BlazerRavagerExplode();
|
|
HEXP ABCDEFGHIJKLMNOPQR 1 Bright
|
|
{
|
|
A_SubExpl(2.);
|
|
A_RavagerSub();
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerWarhead : HellblazerMissile
|
|
{
|
|
void A_BlazerWarheadExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
bRollSprite = false;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("WumboRocketBlast",150);
|
|
A_SetScale(7.);
|
|
SWWMUtility.DoExplosion(self,2000,600000,400,200);
|
|
A_NoGravity();
|
|
A_QuakeEx(9,9,9,150,0,12000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:4000,rollIntensity:2.);
|
|
A_StopSound(CHAN_BODY);
|
|
A_StartSound("hellblazer/hitw",CHAN_WEAPON,attenuation:.4);
|
|
A_StartSound("hellblazer/hitw",CHAN_VOICE,attenuation:.1);
|
|
A_AlertMonsters(swwm_uncapalert?0:40000);
|
|
Spawn("HellblazerExplLight3",pos);
|
|
int numpt = Random[Hellblazer](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](4,20);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(3,2,4)*Random[Hellblazer](48,63));
|
|
s.special1 = Random[Hellblazer](3,8);
|
|
s.scale *= 4.;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[Hellblazer](10,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](4,28);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Hellblazer](20,25);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](10,40);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
|
}
|
|
Spawn("HellblazerRing2",pos);
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,2000,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
|
}
|
|
|
|
void A_WarheadSub()
|
|
{
|
|
if ( special1 < 40 )
|
|
SWWMUtility.DoExplosion(self,320-special1*8,600000-special1*12000,200+special1*30);
|
|
special1++;
|
|
if ( (special1 <= 30) && !(special1%2) )
|
|
{
|
|
int numpt = Random[Hellblazer](0,30-special1);
|
|
double ang, pt;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
ang = FRandom[Hellblazer](0,360);
|
|
pt = FRandom[Hellblazer](-90,90);
|
|
FLineTraceData d;
|
|
Vector3 HitNormal;
|
|
LineTrace(ang,FRandom[Hellblazer](30,40)+20*special1,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("HellblazerSubExpl",d.HitLocation+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = target;
|
|
p.scale *= (3-special1*.02);
|
|
p.alpha *= 1-special1*.02;
|
|
}
|
|
}
|
|
special2++;
|
|
if ( (special2 <= 9) && !(special2%3) )
|
|
{
|
|
int numpt = 5-special2/2;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[Hellblazer](0,360);
|
|
double pt = FRandom[Hellblazer](-90,90);
|
|
let c = Spawn("HellblazerWarheadArm",pos);
|
|
c.angle = ang;
|
|
c.pitch = pt;
|
|
c.target = target;
|
|
}
|
|
}
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1 A_BlazerTick(Color(3,2,4));
|
|
Wait;
|
|
Death:
|
|
TNT1 A 0 A_BlazerWarheadExplode();
|
|
HEXP AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRR 1 Bright A_WarheadSub();
|
|
TNT1 A 1
|
|
{
|
|
A_WarheadSub();
|
|
A_FadeOut(.05);
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Mixin Class HellblazerGrenade
|
|
{
|
|
double rollvel, anglevel, pitchvel;
|
|
Vector3 oldvel;
|
|
|
|
Default
|
|
{
|
|
BounceFactor 1.;
|
|
WallBounceFactor 1.;
|
|
Gravity .35;
|
|
ReactionTime 85;
|
|
-NOGRAVITY;
|
|
+USEBOUNCESTATE;
|
|
+BOUNCEONWALLS;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+ALLOWBOUNCEONACTORS;
|
|
+DONTBOUNCEONSKY;
|
|
+CANBOUNCEWATER;
|
|
+INTERPOLATEANGLES;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
rollvel = FRandom[Hellblazer](-4,4);
|
|
anglevel = FRandom[Hellblazer](-4,4);
|
|
pitchvel = FRandom[Hellblazer](-4,4);
|
|
oldvel = vel;
|
|
}
|
|
override void Tick()
|
|
{
|
|
oldvel = vel;
|
|
Super.Tick();
|
|
if ( isFrozen() || !InStateSequence(CurState,FindState("Spawn")) ) return;
|
|
roll += rollvel;
|
|
angle += anglevel;
|
|
pitch += pitchvel;
|
|
ReactionTime--;
|
|
if ( ReactionTime <= 0 ) ExplodeMissile();
|
|
}
|
|
virtual void A_HandleBounce()
|
|
{
|
|
Vector3 HitNormal = -vel.unit();
|
|
F3DFloor ff;
|
|
if ( BlockingFloor )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
|
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
ff = BlockingFloor.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<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
|
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
ff = BlockingCeiling.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();
|
|
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
|
|
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
|
|
Vector3 RealHitNormal = HitNormal;
|
|
HitNormal = (HitNormal+(FRandom[Hellblazer](-.1,.1),FRandom[Hellblazer](-.1,.1),FRandom[Hellblazer](-.1,.1))).unit();
|
|
if ( (HitNormal dot RealHitNormal) < 0 ) HitNormal *= -.5;
|
|
vel = FRandom[Hellblazer](.8,.9)*((vel dot HitNormal)*HitNormal*(FRandom[Hellblazer](-2.,-1.6))+vel);
|
|
if ( vel.z > 10 ) vel.z = 0.5*(10+vel.z);
|
|
bHITOWNER = true;
|
|
if ( vel.length() < 4. )
|
|
{
|
|
ClearBounce();
|
|
ExplodeMissile();
|
|
return;
|
|
}
|
|
if ( swwm_extraalert ) A_AlertMonsters(swwm_uncapalert?0:300);
|
|
A_StartSound("hellblazer/bounce",CHAN_ITEM);
|
|
rollvel = FRandom[Hellblazer](-16,16);
|
|
anglevel = FRandom[Hellblazer](-16,16);
|
|
pitchvel = FRandom[Hellblazer](-16,16);
|
|
}
|
|
States
|
|
{
|
|
Bounce:
|
|
XZW1 A 0 A_HandleBounce();
|
|
Goto Spawn;
|
|
}
|
|
}
|
|
|
|
// grenades
|
|
Class HellblazerMissile2 : HellblazerMissile
|
|
{
|
|
Mixin HellblazerGrenade;
|
|
}
|
|
|
|
Class HellblazerCrackshot2 : HellblazerCrackshot
|
|
{
|
|
Mixin HellblazerGrenade;
|
|
}
|
|
|
|
Class HellblazerRavager2 : HellblazerRavager
|
|
{
|
|
Mixin HellblazerGrenade;
|
|
}
|
|
|
|
Class HellblazerWarhead2 : HellblazerWarhead
|
|
{
|
|
Mixin HellblazerGrenade;
|
|
}
|
|
|
|
Class HellblazerClusterMini : HellblazerMissile2
|
|
{
|
|
Default
|
|
{
|
|
Radius 2;
|
|
Height 4;
|
|
Speed 20;
|
|
ReactionTime 30;
|
|
}
|
|
|
|
void A_ClusterTick( Color smokecol )
|
|
{
|
|
special2++;
|
|
Vector3 traildir = -(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch));
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
let s = Spawn("SWWMHalfSmoke",level.Vec3Offset(pos,traildir*3));
|
|
s.SetShade(smokecol*Random[Hellblazer](48,63));
|
|
s.scale *= FRandom[Hellblazer](.6,.8);
|
|
s.special1 = Random[Hellblazer](0,1);
|
|
s.alpha *= .4;
|
|
s.vel = .3*vel + (traildir+(FRandom[Hellblazer](-.4,.4),FRandom[Hellblazer](-.4,.4),FRandom[Hellblazer](-.4,.4))).unit()*FRandom[Hellblazer](1.,2.);
|
|
}
|
|
if ( (deto > 1) && (special2 > 5) )
|
|
{
|
|
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.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),60) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
deto++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void A_ClusterExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
bRollSprite = false;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("BigRocketBlast",50);
|
|
A_SetScale(2.5);
|
|
SWWMUtility.DoExplosion(self,80,200000,150,60);
|
|
A_NoGravity();
|
|
A_QuakeEx(4,4,4,12,0,1000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:400,rollIntensity:.6);
|
|
A_StopSound(CHAN_BODY);
|
|
A_StartSound("hellblazer/hitcs",CHAN_WEAPON,attenuation:.9);
|
|
A_StartSound("hellblazer/hitcs",CHAN_VOICE,attenuation:.5);
|
|
A_AlertMonsters(swwm_uncapalert?0:2000);
|
|
Spawn("HellblazerExplLight2",pos);
|
|
int numpt = Random[Hellblazer](4,8);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](1,5);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(2,4,2)*Random[Hellblazer](48,63));
|
|
s.special1 = Random[Hellblazer](1,3);
|
|
s.scale *= 1.5;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[Hellblazer](4,6);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](2,5);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Hellblazer](4,6);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](5,10);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Hellblazer](0.8,1.4);
|
|
}
|
|
let r = Spawn("HellblazerRing",pos);
|
|
r.scale *= .4;
|
|
}
|
|
void A_ClusterSubExpl()
|
|
{
|
|
special1++;
|
|
if ( (special1 > 5) || !(special1%2) ) return;
|
|
int numpt = Random[Hellblazer](0,5-special1);
|
|
double ang, pt;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
ang = FRandom[Hellblazer](0,360);
|
|
pt = FRandom[Hellblazer](-90,90);
|
|
FLineTraceData d;
|
|
Vector3 HitNormal;
|
|
LineTrace(ang,FRandom[Hellblazer](6,12)+6*special1,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("HellblazerSubExpl",d.HitLocation+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = target;
|
|
p.scale *= 1.5-special1*.1;
|
|
p.alpha *= 1-special1*.1;
|
|
}
|
|
}
|
|
override void A_HandleBounce()
|
|
{
|
|
Super.A_HandleBounce();
|
|
if ( !bMISSILE ) return;
|
|
// try to steer towards a target
|
|
let bt = BlockThingsIterator.Create(self,800);
|
|
double closest = double.infinity;
|
|
Actor whomst = null;
|
|
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),800) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
double dist = Distance3D(t);
|
|
if ( dist > closest ) continue;
|
|
closest = dist;
|
|
whomst = t;
|
|
}
|
|
if ( !whomst ) return;
|
|
Vector3 dirto = level.Vec3Diff(pos,whomst.Vec3Offset(0,0,whomst.Height/2));
|
|
dirto /= dirto.length();
|
|
dirto.z += .3;
|
|
double spd = vel.length();
|
|
vel /= spd;
|
|
vel = (vel*.3+dirto*.7)*spd;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1 A_ClusterTick(Color(2,4,2));
|
|
Wait;
|
|
Bounce:
|
|
XZW1 A 0 A_HandleBounce();
|
|
Goto Spawn;
|
|
Death:
|
|
TNT1 A 0 A_ClusterExplode();
|
|
HEXP ABCDEFGHIJKLMNOPQR 1 Bright A_ClusterSubExpl();
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class RavagerLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "DRed";
|
|
Args 0,0,0,400;
|
|
}
|
|
}
|
|
|
|
Class RavagerPuff : Actor
|
|
{
|
|
Vector2 initsc;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale .8;
|
|
Alpha .3;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
+NOTELEPORT;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
scale *= FRandom[Hellblazer](.8,1.);
|
|
alpha *= FRandom[Hellblazer](.8,1.);
|
|
roll = FRandom[Hellblazer](0,360);
|
|
SetState(FindState("Spawn")+Random[Hellblazer](0,19));
|
|
initsc = scale;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
A_FadeOut((waterlevel>0)?.1:.02);
|
|
scale += initsc*.2;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
RFLM ABCDEFGHIJKLMNOPQRST -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerRavagerArm : Actor
|
|
{
|
|
Vector3 oldvel;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_HELLBLAZER";
|
|
DamageType 'Fire';
|
|
PROJECTILE;
|
|
+THRUACTORS;
|
|
+BOUNCEONWALLS;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+USEBOUNCESTATE;
|
|
+NODAMAGETHRUST;
|
|
+FORCERADIUSDMG;
|
|
-NOGRAVITY;
|
|
Gravity 0.15;
|
|
BounceFactor 1.0;
|
|
Radius 2;
|
|
Height 2;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
reactiontime = Random[ExploS](18,24);
|
|
vel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch))*FRandom[ExploS](10.,30.);
|
|
}
|
|
override void Tick()
|
|
{
|
|
oldvel = vel;
|
|
Super.Tick();
|
|
}
|
|
void A_HandleBounce()
|
|
{
|
|
Vector3 HitNormal = -vel.unit();
|
|
F3DFloor ff;
|
|
if ( BlockingFloor )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
|
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
ff = BlockingFloor.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<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
|
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
ff = BlockingCeiling.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();
|
|
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
|
|
HitNormal *= -1;
|
|
}
|
|
else if ( BlockingMobj )
|
|
{
|
|
Vector3 diff = level.Vec3Diff(pos,BlockingMobj.pos);
|
|
if ( (pos.x+radius) <= (BlockingMobj.pos.x-BlockingMobj.radius) )
|
|
HitNormal = (-1,0,0);
|
|
else if ( (pos.x-radius) >= (BlockingMobj.pos.x+BlockingMobj.radius) )
|
|
HitNormal = (1,0,0);
|
|
else if ( (pos.y+radius) <= (BlockingMobj.pos.y-BlockingMobj.radius) )
|
|
HitNormal = (0,-1,0);
|
|
else if ( (pos.y-radius) >= (BlockingMobj.pos.y+BlockingMobj.radius) )
|
|
HitNormal = (0,1,0);
|
|
else if ( pos.z >= (BlockingMobj.pos.z+BlockingMobj.height) )
|
|
HitNormal = (0,0,1);
|
|
else if ( (pos.z+height) <= BlockingMobj.pos.z )
|
|
HitNormal = (0,0,-1);
|
|
}
|
|
// undo the bounce, we need to hook in our own
|
|
vel = oldvel;
|
|
// re-do the bounce with our formula
|
|
vel = .8*((vel dot HitNormal)*HitNormal*FRandom[Hellblazer](-1.5,-1.)+vel);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1
|
|
{
|
|
if ( waterlevel > 0 ) ReactionTime -= 2;
|
|
A_CountDown();
|
|
let p = Spawn("RavagerPuff",pos);
|
|
p.alpha *= .6+.4*(ReactionTime/20.);
|
|
p.scale *= 3.5-2.5*(ReactionTime/20.);
|
|
if ( !(ReactionTime%3) )
|
|
{
|
|
let l = Spawn("RavagerLight",pos);
|
|
l.Args[3] = int(90+50*(ReactionTime/20.));
|
|
l.ReactionTime = int(2+8*(ReactionTime/20.));
|
|
l.target = p;
|
|
}
|
|
if ( !(ReactionTime%1) )
|
|
SWWMUtility.DoExplosion(self,4+reactiontime*2,1000+200*reactiontime,250-6*reactiontime);
|
|
double spd = vel.length();
|
|
vel = (vel*.4+(FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2))).unit()*spd;
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
|
if ( !(ReactionTime%2) )
|
|
{
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel+vel*.2;
|
|
s.SetShade(Color(4,2,2)*Random[ExploS](48,63));
|
|
s.special1 = Random[ExploS](2,4);
|
|
s.scale *= 3.2;
|
|
s.alpha *= .1+.2*(ReactionTime/20.);
|
|
int numpt = Random[Hellblazer](-2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = vel+(FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1),FRandom[Hellblazer](-1,1)).unit()*FRandom[Hellblazer](2,4);
|
|
let s2 = Spawn("SWWMSpark",pos);
|
|
s2.scale *= .4;
|
|
s2.vel = pvel;
|
|
}
|
|
}
|
|
}
|
|
Wait;
|
|
Bounce:
|
|
TNT1 A 0 A_HandleBounce();
|
|
Goto Spawn;
|
|
}
|
|
}
|
|
|
|
Class HellblazerWarheadTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale 2.4;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
HEXP ABCDEFGHIJKLMNOPQR 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerWarheadArm : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_HELLBLAZER";
|
|
DamageType 'Exploded';
|
|
PROJECTILE;
|
|
+THRUACTORS;
|
|
+BOUNCEONWALLS;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+NODAMAGETHRUST;
|
|
+FORCERADIUSDMG;
|
|
-NOGRAVITY;
|
|
Gravity 0.25;
|
|
BounceFactor 1.0;
|
|
Radius 4;
|
|
Height 4;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
reactiontime = Random[ExploS](20,25);
|
|
double ang, pt;
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,90);
|
|
vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[ExploS](20.,35.);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1
|
|
{
|
|
A_CountDown();
|
|
Spawn("HellblazerWarheadTrail",pos);
|
|
SWWMUtility.DoExplosion(self,30+reactiontime*5,3000+500*reactiontime,120+3*reactiontime);
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel+vel*.2;
|
|
s.SetShade(Color(4,3,2)*Random[ExploS](48,63));
|
|
s.special1 = Random[ExploS](1,3);
|
|
s.scale *= 6.;
|
|
s.alpha *= 0.1+.4*(ReactionTime/15.);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class HellblazerX : GhostArtifactX
|
|
{
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1; // not fullbright
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class HellblazerXSub : GhostArtifactX
|
|
{
|
|
Hellblazer weap;
|
|
int ridx;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Normal";
|
|
}
|
|
void UpdateMe()
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
int curtype = 0;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( weap.loadammo != types[i] ) continue;
|
|
curtype = i;
|
|
break;
|
|
}
|
|
static const int sofs[] = {1,7,10,13}; // offsets from SpawnState for each ammo type state label
|
|
int idx;
|
|
switch ( curtype )
|
|
{
|
|
case 0:
|
|
idx = ridx-weap.magpos;
|
|
if ( idx > 5 ) idx -= 6;
|
|
else if ( idx < 0 ) idx += 6;
|
|
if ( weap.magstate[ridx] ) SetState(SpawnState);
|
|
else SetState(SpawnState+sofs[0]+idx);
|
|
break;
|
|
case 1:
|
|
idx = ridx-weap.magpos;
|
|
if ( idx > 2 ) idx -= 3;
|
|
else if ( idx < 0 ) idx += 3;
|
|
if ( (ridx > 2) || weap.magstate[ridx] ) SetState(SpawnState);
|
|
else SetState(SpawnState+sofs[1]+idx);
|
|
break;
|
|
case 2:
|
|
idx = ridx-weap.magpos;
|
|
if ( idx > 2 ) idx -= 3;
|
|
else if ( idx < 0 ) idx += 3;
|
|
if ( (ridx > 2) || weap.magstate[ridx] ) SetState(SpawnState);
|
|
else SetState(SpawnState+sofs[2]+idx);
|
|
break;
|
|
case 3:
|
|
idx = ridx-weap.magpos;
|
|
if ( idx > 1 ) idx -= 2;
|
|
else if ( idx < 0 ) idx += 2;
|
|
if ( (ridx > 1) || weap.magstate[ridx] ) SetState(SpawnState);
|
|
else SetState(SpawnState+sofs[3]+idx);
|
|
break;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A -1;
|
|
Missiles:
|
|
XZW1 ABCDEF -1;
|
|
Crackshots:
|
|
XZW2 ABC -1;
|
|
Ravagers:
|
|
XZW3 ABC -1;
|
|
Nukes:
|
|
XZW4 AB -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class Hellblazer : SWWMWeapon
|
|
{
|
|
int clipcount;
|
|
bool magstate[6]; // true: rocket was spent
|
|
int magpos; // current rotation
|
|
Class<Ammo> loadammo, nextammo;
|
|
int spinskipped;
|
|
HellblazerXSub pickuprockets[6];
|
|
|
|
Property ClipCount : clipcount;
|
|
|
|
transient ui TextureID WeaponBox, AmmoIcon[4], LoadedIcon[4];
|
|
transient ui Font TewiFont;
|
|
|
|
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
|
|
if ( !WeaponBox )
|
|
{
|
|
WeaponBox = TexMan.CheckForTexture("graphics/HUD/HellblazerDisplay.png",TexMan.Type_Any);
|
|
AmmoIcon[0] = TexMan.CheckForTexture("graphics/HUD/HellblazerMissile.png",TexMan.Type_Any);
|
|
AmmoIcon[1] = TexMan.CheckForTexture("graphics/HUD/HellblazerCrackshot.png",TexMan.Type_Any);
|
|
AmmoIcon[2] = TexMan.CheckForTexture("graphics/HUD/HellblazerRavager.png",TexMan.Type_Any);
|
|
AmmoIcon[3] = TexMan.CheckForTexture("graphics/HUD/HellblazerWarhead.png",TexMan.Type_Any);
|
|
LoadedIcon[0] = TexMan.CheckForTexture("graphics/HUD/HellblazerMissileLoaded.png",TexMan.Type_Any);
|
|
LoadedIcon[1] = TexMan.CheckForTexture("graphics/HUD/HellblazerCrackshotLoaded.png",TexMan.Type_Any);
|
|
LoadedIcon[2] = TexMan.CheckForTexture("graphics/HUD/HellblazerRavagerLoaded.png",TexMan.Type_Any);
|
|
LoadedIcon[3] = TexMan.CheckForTexture("graphics/HUD/HellblazerWarheadLoaded.png",TexMan.Type_Any);
|
|
}
|
|
double xx = -56, yy = -49;
|
|
Screen.DrawTexture(WeaponBox,false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
int curtype = 0;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( loadammo != types[i] ) continue;
|
|
curtype = i;
|
|
break;
|
|
}
|
|
xx += 2;
|
|
yy += 1;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
int amt = Owner.CountInv(types[i]);
|
|
String amtstr = String.Format("%3d",amt);
|
|
Screen.DrawText(TewiFont,Font.CR_FIRE,bx+xx,by+yy,amtstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(types[i]==nextammo)?Color(0,0,0,0):Color(128,0,0,0));
|
|
Screen.DrawTexture(AmmoIcon[i],false,bx+xx+19,by+yy+1,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(types[i]==nextammo)?Color(0,0,0,0):Color(128,0,0,0));
|
|
yy += 13;
|
|
if ( i%2 )
|
|
{
|
|
yy -= 26;
|
|
xx += 28;
|
|
}
|
|
}
|
|
yy = -18;
|
|
switch ( curtype )
|
|
{
|
|
case 0:
|
|
xx = -54;
|
|
for ( int i=0; i<6; i++ )
|
|
{
|
|
Screen.DrawTexture(LoadedIcon[0],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0),DTA_Desaturate,magstate[i]?192:0);
|
|
xx += 9;
|
|
}
|
|
break;
|
|
case 1:
|
|
xx = -49;
|
|
for ( int i=0; i<3; i++ )
|
|
{
|
|
Screen.DrawTexture(LoadedIcon[1],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0),DTA_Desaturate,magstate[i]?192:0);
|
|
xx += 18;
|
|
}
|
|
break;
|
|
case 2:
|
|
xx = -49;
|
|
for ( int i=0; i<3; i++ )
|
|
{
|
|
Screen.DrawTexture(LoadedIcon[2],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0),DTA_Desaturate,magstate[i]?192:0);
|
|
xx += 18;
|
|
}
|
|
break;
|
|
case 3:
|
|
xx = -45;
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
Screen.DrawTexture(LoadedIcon[3],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0),DTA_Desaturate,magstate[i]?192:0);
|
|
xx += 27;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
override Vector3 GetTraceOffset()
|
|
{
|
|
return (10.,3.5,-5.);
|
|
}
|
|
|
|
action void A_HellblazerFire( int type = 0, bool bAlt = false )
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
static const Class<Actor> projs[] = {"HellblazerMissile","HellblazerCrackshot","HellblazerRavager","HellblazerWarhead",
|
|
"HellblazerMissile2","HellblazerCrackshot2","HellblazerRavager2","HellblazerWarhead2"};
|
|
static const Color cols[] = {Color(4,3,2),Color(2,4,2),Color(4,2,2),Color(3,2,4)};
|
|
A_StartSound(bAlt?"hellblazer/altfire":"hellblazer/fire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:(bAlt?1.7:.8));
|
|
A_AlertMonsters(swwm_uncapalert?0:bAlt?400:1200);
|
|
int qstr = bAlt?4:5;
|
|
A_QuakeEx(qstr,qstr,qstr,bAlt?4:12,0,8,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.12*qstr);
|
|
A_ZoomFactor(bAlt?.96:.93,ZOOM_INSTANT);
|
|
A_ZoomFactor(1.);
|
|
A_PlayerFire();
|
|
invoker.clipcount = max(0,invoker.clipcount-1);
|
|
invoker.magstate[invoker.magpos] = true;
|
|
invoker.spinskipped++;
|
|
Vector3 x, y, z, x2, y2, z2, dir, origin;
|
|
double a, s;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
SWWMUtility.DoKnockback(self,-x,bAlt?22000.:32000.);
|
|
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3.5*y-5*z);
|
|
a = FRandom[Hellblazer](0,360);
|
|
s = FRandom[Hellblazer](0,bAlt?.02:.005);
|
|
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
|
let p = Spawn(projs[type+4*bAlt],origin);
|
|
p.target = self;
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = asin(-dir.z);
|
|
p.vel = dir*p.speed;
|
|
if ( bAlt )
|
|
{
|
|
p.vel.z += 3.5;
|
|
return;
|
|
}
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
let s = Spawn("SWWMViewSmoke",origin);
|
|
SWWMViewSmoke(s).ofs = (10,3,-5);
|
|
s.target = self;
|
|
s.SetShade(cols[type]*Random[Hellblazer](48,63));
|
|
s.alpha *= .2;
|
|
s.scale *= 2.;
|
|
}
|
|
for ( int i=0; i<5; i++ )
|
|
{
|
|
let s = Spawn("SWWMSmoke",origin);
|
|
s.special1 = 1;
|
|
s.scale *= 2.4;
|
|
s.alpha *= .4;
|
|
s.SetShade(cols[type]*Random[Hellblazer](48,63));
|
|
s.vel += vel*.5+x*FRandom[Hellblazer](6.,10.)+y*FRandom[Hellblazer](-2,2)+z*FRandom[Hellblazer](-2,2);
|
|
}
|
|
for ( int i=0; i<6; i++ )
|
|
{
|
|
let s = Spawn("SWWMSpark",origin);
|
|
s.scale *= .7;
|
|
s.alpha *= .4;
|
|
s.vel += vel*.5+x*FRandom[Hellblazer](4.,8.)+y*FRandom[Hellblazer](-2,2)+z*FRandom[Hellblazer](-2,2);
|
|
}
|
|
}
|
|
|
|
override bool ReportHUDAmmo()
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
for ( int i=0; i<4; i++ ) if ( Owner.CountInv(types[i]) > 0 ) return true;
|
|
return (clipcount>0);
|
|
}
|
|
|
|
override bool CheckAmmo( int firemode, bool autoswitch, bool requireammo, int ammocount )
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
if ( (firemode == PrimaryFire) || (firemode == AltFire) )
|
|
{
|
|
if ( clipcount > 0 ) return true;
|
|
for ( int i=0; i<4; i++ ) if ( Owner.CountInv(types[i]) > 0 ) return true;
|
|
return false;
|
|
}
|
|
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
|
|
}
|
|
|
|
override bool UsesAmmo( Class<Ammo> kind )
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
for ( int i=0; i<4; i++ ) if ( kind is types[i] ) return true;
|
|
return false;
|
|
}
|
|
|
|
action void A_GlassOverlay( StateLabel g )
|
|
{
|
|
if ( !player.FindPSprite(PSP_WEAPON+1) )
|
|
{
|
|
A_Overlay(PSP_WEAPON+1,g);
|
|
A_OverlayFlags(PSP_WEAPON+1,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
|
|
A_OverlayRenderStyle(PSP_WEAPON+1,STYLE_Add);
|
|
}
|
|
else player.SetPSprite(PSP_WEAPON+1,invoker.FindState(g));
|
|
}
|
|
|
|
action state A_JumpByAmmoType( StateLabel a, StateLabel b, StateLabel c, StateLabel d, StateLabel g, StateLabel o = null )
|
|
{
|
|
A_Overlay(-9999,o);
|
|
A_GlassOverlay(g);
|
|
if ( invoker.loadammo is "HellblazerMissiles" ) return invoker.FindState(a);
|
|
if ( invoker.loadammo is "HellblazerCrackshots" ) return invoker.FindState(b);
|
|
if ( invoker.loadammo is "HellblazerRavagers" ) return invoker.FindState(c);
|
|
if ( invoker.loadammo is "HellblazerWarheads" ) return invoker.FindState(d);
|
|
return invoker.FindState(a);
|
|
}
|
|
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
if ( !loadammo ) loadammo = "HellblazerMissiles";
|
|
nextammo = loadammo;
|
|
}
|
|
|
|
clearscope int LoadedCapacity() const
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
static const int typeclipcount[] = {6,3,3,2};
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( loadammo != types[i] ) continue;
|
|
let a = Owner.FindInventory(types[i]);
|
|
return min(a.Amount+clipcount,typeclipcount[i]);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
action void A_PickNextAmmo()
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
int curidx = 0;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( invoker.nextammo != types[i] ) continue;
|
|
curidx = (i+1)%4;
|
|
break;
|
|
}
|
|
Class<Ammo> oldammo = invoker.nextammo, newammo = invoker.loadammo;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
int nidx = (i+curidx)%4;
|
|
if ( CountInv(types[nidx]) <= 0 ) continue;
|
|
newammo = types[nidx];
|
|
break;
|
|
}
|
|
if ( newammo != oldammo ) A_StartSound("misc/invchange",CHAN_WEAPONEXTRA,CHANF_UI|CHANF_LOCAL);
|
|
invoker.nextammo = newammo;
|
|
}
|
|
|
|
action void A_ZoomHold()
|
|
{
|
|
A_WeaponReady(WRF_NOFIRE);
|
|
if ( player.cmd.buttons&BT_ZOOM ) return;
|
|
player.SetPSPrite(PSP_WEAPON,invoker.FindState("Ready"));
|
|
}
|
|
|
|
action void A_SwapAmmo()
|
|
{
|
|
let amo = FindInventory(invoker.loadammo);
|
|
// if we're loading the same ammo type, we only need to remove the needed ammo
|
|
if ( invoker.loadammo == invoker.nextammo )
|
|
{
|
|
int takeamt = invoker.LoadedCapacity()-invoker.clipcount;
|
|
invoker.clipcount = invoker.LoadedCapacity();
|
|
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
|
amo.Amount = max(0,amo.Amount-takeamt);
|
|
invoker.magpos = 0;
|
|
for ( int i=0; i<6; i++ )
|
|
invoker.magstate[i] = !(invoker.clipcount > i);
|
|
return;
|
|
}
|
|
// re-add/drop any still loaded
|
|
int maxgiveamt = min(amo.MaxAmount-amo.Amount,invoker.clipcount);
|
|
int dropamt = invoker.clipcount-maxgiveamt;
|
|
if ( (dropamt > 0) && !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) amo.CreateTossable(dropamt);
|
|
amo.Amount = min(amo.MaxAmount,amo.Amount+invoker.clipcount);
|
|
// swap
|
|
invoker.clipcount = 0;
|
|
invoker.loadammo = invoker.nextammo;
|
|
invoker.clipcount = invoker.LoadedCapacity();
|
|
invoker.magpos = 0;
|
|
for ( int i=0; i<6; i++ )
|
|
invoker.magstate[i] = !(invoker.clipcount > i);
|
|
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
|
{
|
|
let namo = FindInventory(invoker.loadammo);
|
|
namo.Amount = max(0,namo.Amount-invoker.clipcount);
|
|
}
|
|
}
|
|
|
|
action void A_HellblazerReady()
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
int flg = WRF_ALLOWRELOAD|WRF_ALLOWZOOM|WRF_ALLOWUSER1;
|
|
// can we fire?
|
|
bool canfire = (invoker.clipcount > 0);
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( CountInv(types[i]) <= 0 ) continue;
|
|
canfire = true;
|
|
break;
|
|
}
|
|
if ( !canfire ) flg |= WRF_NOPRIMARY|WRF_NOSECONDARY;
|
|
A_WeaponReady(flg);
|
|
if ( player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK) )
|
|
invoker.CheckAmmo(EitherFire,true);
|
|
}
|
|
|
|
// check if weapon was dropped or interrupted in some way before the mag spin could be done
|
|
action void A_CheckSpinSkip()
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
static const int magcap[] = {6,3,3,2};
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( invoker.loadammo != types[i] ) continue;
|
|
invoker.magpos = (invoker.magpos+invoker.spinskipped)%magcap[i];
|
|
invoker.spinskipped = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
action void A_UpdatePickup()
|
|
{
|
|
static const Class<Ammo> types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"};
|
|
for ( int i=0; i<6; i++ )
|
|
{
|
|
if ( !invoker.pickuprockets[i] )
|
|
{
|
|
invoker.pickuprockets[i] = HellblazerXSub(Spawn("HellblazerXSub",pos));
|
|
invoker.pickuprockets[i].angle = angle;
|
|
invoker.pickuprockets[i].target = invoker;
|
|
invoker.pickuprockets[i].weap = invoker;
|
|
invoker.pickuprockets[i].FloatBobPhase = FloatBobPhase;
|
|
invoker.pickuprockets[i].ridx = i;
|
|
}
|
|
invoker.pickuprockets[i].UpdateMe();
|
|
}
|
|
int curtype = 0;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( invoker.loadammo != types[i] ) continue;
|
|
curtype = i;
|
|
break;
|
|
}
|
|
SetState(SpawnState+curtype+1);
|
|
}
|
|
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("HellblazerX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("HellblazerX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_HELLBLAZER";
|
|
Inventory.PickupMessage "$I_HELLBLAZER";
|
|
Obituary "$O_HELLBLAZER";
|
|
Inventory.Icon "graphics/HUD/Icons/W_Hellblazer.png";
|
|
Weapon.SlotNumber 6;
|
|
Weapon.SelectionOrder 700;
|
|
Weapon.UpSound "hellblazer/select";
|
|
Stamina 90000;
|
|
Weapon.AmmoType1 "HellblazerMissiles";
|
|
Weapon.AmmoGive1 6;
|
|
//SWWMWeapon.SwapWeapon "Quadravol";
|
|
SWWMWeapon.DropAmmoType "RocketAmmo";
|
|
Hellblazer.ClipCount 6;
|
|
+SWWMWEAPON.NOFIRSTGIVE;
|
|
+WEAPON.EXPLOSIVE;
|
|
Radius 24;
|
|
Height 32;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1 NoDelay A_UpdatePickup();
|
|
XZW1 ABCD -1;
|
|
Stop;
|
|
Select:
|
|
XZW2 I 0
|
|
{
|
|
A_CheckSpinSkip();
|
|
A_FullRaise();
|
|
return A_JumpByAmmoType("Select_1","Select_2","Select_3","Select_4","Select_G");
|
|
}
|
|
Select_1:
|
|
XZW2 IJKLMNOP 2;
|
|
Goto Ready_1;
|
|
Select_2:
|
|
XZW7 DEFGHIJK 2;
|
|
Goto Ready_2;
|
|
Select_3:
|
|
XZWC BCDEFGHI 2;
|
|
Goto Ready_3;
|
|
Select_4:
|
|
XZWG Z 2;
|
|
XZWH ABCDEFG 2;
|
|
Goto Ready_4;
|
|
Select_G:
|
|
XZWM ABCDEFGH 2;
|
|
Goto Ready_G;
|
|
Deselect:
|
|
XZW2 A 0
|
|
{
|
|
A_StartSound("hellblazer/deselect",CHAN_WEAPON,CHANF_OVERLAP);
|
|
return A_JumpByAmmoType("Deselect_1","Deselect_2","Deselect_3","Deselect_4","Deselect_G");
|
|
}
|
|
Deselect_1:
|
|
XZW2 ABCDEFGHI 2;
|
|
XZW2 I -1 A_FullLower();
|
|
Stop;
|
|
Deselect_2:
|
|
XZW6 VWXYZ 2;
|
|
XZW7 ABCD 2;
|
|
XZW7 D -1 A_FullLower();
|
|
Stop;
|
|
Deselect_3:
|
|
XZWB TUVWXYZ 2;
|
|
XZWC AB 2;
|
|
XZWC B -1 A_FullLower();
|
|
Stop;
|
|
Deselect_4:
|
|
XZWG RSTUVWXYZ 2;
|
|
XZWG Z -1 A_FullLower();
|
|
Stop;
|
|
Deselect_G:
|
|
XZWL STUVWXYZ 2;
|
|
XZWM A 2;
|
|
Stop;
|
|
Ready:
|
|
XZW2 A 0 A_JumpByAmmoType("Ready_1","Ready_2","Ready_3","Ready_4","Ready_G");
|
|
Ready_1:
|
|
XZW2 A 1 A_HellblazerReady();
|
|
Wait;
|
|
Ready_2:
|
|
XZW6 V 1 A_HellblazerReady();
|
|
Wait;
|
|
Ready_3:
|
|
XZWB T 1 A_HellblazerReady();
|
|
Wait;
|
|
Ready_4:
|
|
XZWG R 1 A_HellblazerReady();
|
|
Wait;
|
|
Ready_G:
|
|
XZWL S 1;
|
|
Wait;
|
|
Fire:
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.clipcount <= 0 )
|
|
{
|
|
if ( CountInv(invoker.nextammo) <= 0 ) A_PickNextAmmo();
|
|
return A_JumpByAmmoType("Unload_1","Unload_2","Unload_3","Unload_4","Unload_G");
|
|
}
|
|
return A_JumpByAmmoType("Fire_1","Fire_2","Fire_3","Fire_4","Fire_G");
|
|
}
|
|
Fire_1:
|
|
XZW2 A 1 A_HellblazerFire(0);
|
|
XZW2 QRSTUVW 2;
|
|
Goto Cycle_1;
|
|
Fire_2:
|
|
XZW6 V 1 A_HellblazerFire(1);
|
|
XZW7 LMNOPQR 2;
|
|
Goto Cycle_2;
|
|
Fire_3:
|
|
XZWB T 1 A_HellblazerFire(2);
|
|
XZWC JKLMNOP 2;
|
|
Goto Cycle_3;
|
|
Fire_4:
|
|
XZWG R 1 A_HellblazerFire(3);
|
|
XZWH HIJKLMN 2;
|
|
Goto Cycle_4;
|
|
Fire_G:
|
|
XZWL S 1;
|
|
XZWM IJKLMNO 2;
|
|
Goto Ready_G; // state jump to cycling is done elsewhere
|
|
AltFire:
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.clipcount <= 0 )
|
|
{
|
|
if ( CountInv(invoker.nextammo) <= 0 ) A_PickNextAmmo();
|
|
return A_JumpByAmmoType("Unload_1","Unload_2","Unload_3","Unload_4","Unload_G");
|
|
}
|
|
return A_JumpByAmmoType("AltFire_1","AltFire_2","AltFire_3","AltFire_4","AltFire_G");
|
|
}
|
|
AltFire_1:
|
|
XZW2 A 1 A_HellblazerFire(0,true);
|
|
XZW2 XYZ 2;
|
|
XZW3 ABCD 2;
|
|
Goto Cycle_1;
|
|
AltFire_2:
|
|
XZW6 V 1 A_HellblazerFire(1,true);
|
|
XZW7 STUVWXY 2;
|
|
Goto Cycle_2;
|
|
AltFire_3:
|
|
XZWB T 1 A_HellblazerFire(2,true);
|
|
XZWC QRSTUVW 2;
|
|
Goto Cycle_3;
|
|
AltFire_4:
|
|
XZWG R 1 A_HellblazerFire(3,true);
|
|
XZWH OPQRSTU 2;
|
|
Goto Cycle_4;
|
|
AltFire_G:
|
|
XZWL S 1;
|
|
XZWM PQRSTUV 2;
|
|
Goto Ready_G; // state jump to cycling is done elsewhere
|
|
Cycle_1:
|
|
XZW2 A 3
|
|
{
|
|
invoker.spinskipped--;
|
|
invoker.magpos = (invoker.magpos+1)%6;
|
|
A_GlassOverlay("Cycle_G1");
|
|
}
|
|
XZW3 E 3;
|
|
XZW3 FGHI 2;
|
|
XZW3 I 0;
|
|
XZW3 FE 3;
|
|
Goto Ready_1;
|
|
Cycle_2:
|
|
XZW6 V 3
|
|
{
|
|
invoker.spinskipped--;
|
|
invoker.magpos = (invoker.magpos+1)%3;
|
|
A_GlassOverlay("Cycle_G2");
|
|
}
|
|
XZW7 Z 3;
|
|
XZW8 ABCDEFG 2;
|
|
XZW8 G 0;
|
|
XZW8 A 3;
|
|
XZW7 Z 3;
|
|
Goto Ready_2;
|
|
Cycle_3:
|
|
XZWB T 3
|
|
{
|
|
invoker.spinskipped--;
|
|
invoker.magpos = (invoker.magpos+1)%3;
|
|
A_GlassOverlay("Cycle_G2");
|
|
}
|
|
XZWC X 3;
|
|
XZWC YZ 2;
|
|
XZWD ABCDE 2;
|
|
XZWD E 0;
|
|
XZWC YX 3;
|
|
Goto Ready_3;
|
|
Cycle_4:
|
|
XZWG R 3
|
|
{
|
|
invoker.spinskipped--;
|
|
invoker.magpos = (invoker.magpos+1)%2;
|
|
A_GlassOverlay("Cycle_G3");
|
|
}
|
|
XZWH V 3;
|
|
XZWH WXYZ 2;
|
|
XZWI ABCDEF 2;
|
|
XZWI F 0;
|
|
XZWH WV 3;
|
|
Goto Ready_4;
|
|
Cycle_G1:
|
|
XZWL S 3 A_StartSound("hellblazer/shift",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWM W 3;
|
|
XZWM X 2 A_StartSound("hellblazer/spin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWM YZ 2;
|
|
XZWN A 2;
|
|
XZWN A 0 A_StartSound("hellblazer/shift",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWM XW 3;
|
|
Goto Ready_G;
|
|
Cycle_G2:
|
|
XZWL S 3 A_StartSound("hellblazer/shift",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWM W 3;
|
|
XZWN B 2 A_StartSound("hellblazer/spin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN CD 2;
|
|
XZWN E 2 A_StartSound("hellblazer/spin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN FGH 2;
|
|
XZWN H 0 A_StartSound("hellblazer/shift",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN B 3;
|
|
XZWM W 3;
|
|
Goto Ready_G;
|
|
Cycle_G3:
|
|
XZWL S 3 A_StartSound("hellblazer/shift",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWM W 3;
|
|
XZWN I 2 A_StartSound("hellblazer/spin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN JK 2;
|
|
XZWN L 2 A_StartSound("hellblazer/spin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN MN 2;
|
|
XZWN O 2 A_StartSound("hellblazer/spin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN PQR 2;
|
|
XZWN R 0 A_StartSound("hellblazer/shift",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN I 3;
|
|
XZWM W 3;
|
|
Goto Ready_G;
|
|
Reload:
|
|
XZW2 A 2
|
|
{
|
|
if ( (invoker.clipcount <= 0) && (CountInv(invoker.nextammo) <= 0) ) A_PickNextAmmo();
|
|
if ( (invoker.clipcount >= invoker.LoadedCapacity()) && (invoker.loadammo == invoker.nextammo) )
|
|
return A_JumpByAmmoType("Idle_1","Idle_2","Idle_3","Idle_4","Idle_G");
|
|
return A_JumpByAmmoType("Unload_1","Unload_2","Unload_3","Unload_4","Unload_G");
|
|
}
|
|
Goto Ready;
|
|
Unload_1:
|
|
XZW2 A 2;
|
|
XZW3 JKLMNOPQRSTUVWXYZ 2;
|
|
XZW4 ABCDEFGHIJ 2;
|
|
XZWR JKLMN 3;
|
|
XZW4 J 2
|
|
{
|
|
A_SwapAmmo();
|
|
return A_JumpByAmmoType("Load_1","Load_2","Load_3","Load_4","Load_G");
|
|
}
|
|
Goto Load_1;
|
|
Unload_2:
|
|
XZW6 V 2;
|
|
XZW8 HIJKLMNOPQRSTUVWXYZ 2;
|
|
XZW9 ABCDEFGH 2;
|
|
XZWR JKLMN 3;
|
|
XZW9 H 2
|
|
{
|
|
A_SwapAmmo();
|
|
return A_JumpByAmmoType("Load_1","Load_2","Load_3","Load_4","Load_G");
|
|
}
|
|
Goto Load_2;
|
|
Unload_3:
|
|
XZWB T 2;
|
|
XZWD FGHIJKLMNOPQRSTUVWXYZ 2;
|
|
XZWE ABCDEF 2;
|
|
XZWR JKLMN 3;
|
|
XZWE F 2
|
|
{
|
|
A_SwapAmmo();
|
|
return A_JumpByAmmoType("Load_1","Load_2","Load_3","Load_4","Load_G");
|
|
}
|
|
Goto Load_3;
|
|
Unload_4:
|
|
XZWG R 2;
|
|
XZWI GHIJKLMNOPQRSTUVWXYZ 2;
|
|
XZWJ ABCDEFG 2;
|
|
XZWR JKLMN 3;
|
|
XZWJ G 2
|
|
{
|
|
A_SwapAmmo();
|
|
return A_JumpByAmmoType("Load_1","Load_2","Load_3","Load_4","Load_G");
|
|
}
|
|
Goto Load_4;
|
|
Unload_G:
|
|
XZWL S 2 A_StartSound("hellblazer/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN STU 2;
|
|
XZWN V 2 A_StartSound("hellblazer/open",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWN WXYZ 2;
|
|
XZWO ABCDEFGH 2;
|
|
XZWO I 2 A_StartSound("hellblazer/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWO JKLMNOPQRS 2;
|
|
XZWR EFGHI 3;
|
|
Goto Load_G;
|
|
Load_1:
|
|
XZW4 JKLMNOPQRSTUVWXYZ 2;
|
|
XZW5 ABCDEFGHIJ 2;
|
|
Goto Ready_1;
|
|
Load_2:
|
|
XZW9 HIJKLMNOPQRSTUVWXYZ 2;
|
|
XZWA ABCDEFGH 2;
|
|
Goto Ready_2;
|
|
Load_3:
|
|
XZWE FGHIJKLMNOPQRSTUVWXYZ 2;
|
|
XZWF ABCDEF 2;
|
|
Goto Ready_3;
|
|
Load_4:
|
|
XZWJ GHIJKLMNOPQRSTUVWXYZ 2;
|
|
XZWK ABCDEFG 2;
|
|
Goto Ready_4;
|
|
Load_G:
|
|
XZWO S 2 A_PlayerReload();
|
|
XZWO TUVWXY 2;
|
|
XZWO Z 2 A_StartSound("hellblazer/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWP ABCDEFG 2;
|
|
XZWP H 2 A_StartSound("hellblazer/close",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWP IJKL 2;
|
|
XZWP M 2 A_StartSound("hellblazer/meleestop",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWP NOPQRS 2;
|
|
Goto Ready_G;
|
|
Idle_1:
|
|
XZW2 A 2;
|
|
XZW5 KLMNOPQRSTUVWXYZ 2;
|
|
XZW6 A 2;
|
|
Goto Ready_1;
|
|
Idle_2:
|
|
XZW6 V 2;
|
|
XZWA IJKLMNOPQRSTUVWXY 2;
|
|
Goto Ready_2;
|
|
Idle_3:
|
|
XZWB T 2;
|
|
XZWF GHIJKLMNOPQRSTUVW 2;
|
|
Goto Ready_3;
|
|
Idle_4:
|
|
XZWG R 2;
|
|
XZWK HIJKLMNOPQRSTUVWX 2;
|
|
Goto Ready_4;
|
|
Idle_G:
|
|
XZWL S 2
|
|
{
|
|
A_StartSound("hellblazer/idle",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerCheckGun();
|
|
}
|
|
XZWP TUVWX 2;
|
|
XZWP Y 2 A_StartSound("hellblazer/dustoff",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWP Z 2;
|
|
XZWQ ABCDEFGHIJ 2;
|
|
Goto Ready_G;
|
|
Zoom:
|
|
#### # 1
|
|
{
|
|
A_PickNextAmmo();
|
|
A_WeaponReady(WRF_NOFIRE);
|
|
}
|
|
#### # 1 A_ZoomHold();
|
|
Wait;
|
|
User1:
|
|
XZW2 A 0 A_JumpByAmmoType("User1_1","User1_2","User1_3","User1_4","User1_G");
|
|
User1_1:
|
|
XZW2 A 2;
|
|
XZW6 BCDE 2;
|
|
XZW6 FGH 1;
|
|
XZW6 IJK 2;
|
|
XZW6 LMNOPQRSTU 2;
|
|
Goto Ready_1;
|
|
User1_2:
|
|
XZW6 V 2;
|
|
XZWA Z 2;
|
|
XZWB ABC 2;
|
|
XZWB DEF 1;
|
|
XZWB GHI 2;
|
|
XZWB JKLMNOPQRS 2;
|
|
Goto Ready_2;
|
|
User1_3:
|
|
XZWB T 2;
|
|
XZWF XYZ 2;
|
|
XZWG A 2;
|
|
XZWG BCD 1;
|
|
XZWG EFG 2;
|
|
XZWG HIJKLMNOPQ 2;
|
|
Goto Ready_3;
|
|
User1_4:
|
|
XZWG R 2;
|
|
XZWK YZ 2;
|
|
XZWL AB 2;
|
|
XZWL CDE 1;
|
|
XZWL FGH 2;
|
|
XZWL IJKLMNOPQR 2;
|
|
Goto Ready_4;
|
|
User1_G:
|
|
XZWL S 2
|
|
{
|
|
A_StartSound("hellblazer/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerMelee();
|
|
}
|
|
XZWQ KLM 2;
|
|
XZWQ N 2 A_Parry(9);
|
|
XZWQ OP 1;
|
|
XZWQ Q 1 A_Melee(75,"demolitionist/whitl",1.05);
|
|
XZWQ RSTUV 2;
|
|
XZWQ W 2 A_StartSound("hellblazer/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWQ XYZ 2;
|
|
XZWR ABCD 2;
|
|
Goto Ready_G;
|
|
}
|
|
}
|