swwmgz_m/zscript/swwm_blazeit.zsc

1957 lines
51 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 Hellblazer : SWWMWeapon
{
int clipcount;
bool magstate[6]; // true: rocket was spent
int magpos; // current rotation
Class<Ammo> loadammo, nextammo;
int spinskipped;
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;
}
}
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.DropAmmoType "RocketAmmo";
Hellblazer.ClipCount 6;
+SWWMWEAPON.NOFIRSTGIVE;
+WEAPON.EXPLOSIVE;
Radius 24;
Height 32;
}
States
{
Spawn:
XZW1 A -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;
}
}