flak_m/zscript/shockrifle.zsc
Marisa Kirisame c0c4023adf Additional 3D floor support code.
Added missing boss land grunt from beta files.
Correction: A specific death sound for male and female classes is meant to be used for decapitation.
2019-09-11 16:52:02 +02:00

1379 lines
31 KiB
Text

Class ShockAmmo : Ammo
{
Default
{
Tag "$T_SHOCKAMMO";
Inventory.PickupMessage "$I_SHOCKAMMO";
Inventory.Amount 10;
Inventory.MaxAmount 50;
Ammo.BackpackAmount 20;
Ammo.BackpackMaxAmount 100;
Ammo.DropAmount 5;
}
States
{
Spawn:
SHOA A -1;
Stop;
}
}
Class ShockAmmo2 : ShockAmmo
{
Default
{
Tag "$T_SHOCKAMMO2";
Inventory.PickupMessage "$I_SHOCKAMMO2";
Inventory.Amount 3;
Ammo.DropAmount 3;
}
States
{
Spawn:
SHOA A -1;
Stop;
}
}
Class ShockBeamTracer : LineTracer
{
Actor owner, ignore, lasthit;
override ETraceStatus TraceCallback()
{
if ( Results.HitType == TRACE_HitActor )
{
if ( (Results.HitActor == owner) || (Results.HitActor == ignore) || (Results.HitActor == lasthit) ) return TRACE_Skip;
if ( Results.HitActor.bSHOOTABLE || Results.HitActor is 'ShockHitbox' ) return TRACE_Stop;
return TRACE_Skip;
}
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
{
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
return TRACE_Stop;
return TRACE_Skip;
}
return TRACE_Stop;
}
}
Class ShockRifleWave : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
Scale 0.7;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
alpha -= 1/50.;
}
States
{
Spawn:
SWAV A 50 Bright;
SWAV B 0 Bright;
Stop;
}
}
Class SuperShockRifleWave : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
Scale 1.2;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
alpha -= 1/50.;
}
States
{
Spawn:
SWAV A 50 Bright;
SWAV B 0 Bright;
Stop;
}
}
Class ShockBeamRing : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
Scale 0.5;
ReactionTime 18;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
alpha -= 1./ReactionTime;
}
States
{
Spawn:
SRNG ABCDEFGHI 2 Bright;
Stop;
}
}
Class SuperShockBeamRing : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
Scale 0.9;
ReactionTime 18;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
alpha -= 1./ReactionTime;
}
States
{
Spawn:
SRNG ABCDEFGHI 2 Bright;
Stop;
}
}
Class ShockBlastRing : ShockBeamRing
{
Default
{
Scale 3.0;
ReactionTime 45;
}
States
{
Spawn:
SRNG ABCDEFGHI 5 Bright;
Stop;
}
}
Class SuperShockBlastRing : ShockBeamRing
{
Default
{
Scale 5.0;
ReactionTime 45;
}
States
{
Spawn:
SRNG ABCDEFGHI 5 Bright;
Stop;
}
}
Class ShockSpark : Actor
{
Default
{
RenderStyle "Add";
Radius 2;
Height 2;
+NOBLOCKMAP;
+NOGRAVITY;
+MISSILE;
+FORCEXYBILLBOARD;
+THRUACTORS;
+ROLLSPRITE;
+ROLLCENTER;
+NOTELEPORT;
+DONTSPLASH;
+CANBOUNCEWATER;
-BOUNCEAUTOOFF;
BounceType "Doom";
BounceFactor 1.0;
WallBounceFactor 1.0;
Scale 0.1;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( !bAMBUSH )
{
roll = FRandom[ASMD](0,360);
let s = Spawn(GetClass(),pos);
s.bAMBUSH = true;
s.vel = vel;
s.scale = scale;
s.roll = roll;
}
}
States
{
Spawn:
ASMK A 1 Bright
{
A_FadeOut(FRandom[ASMD](0.0,0.1));
vel *= 0.98;
}
Wait;
}
}
Class ShockSparkTrail : ShockSpark
{
Default
{
+AMBUSH;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
roll = FRandom[ASMD](0,360);
}
States
{
Spawn:
ASMK A 1 Bright A_FadeOut(FRandom[ASMD](0.0,0.2));
Wait;
}
}
Class ShockBeam : Actor
{
ShockBeamTracer t;
Vector3 tracedir;
bool moving;
double totaldist;
Default
{
Obituary "$O_SHOCKRIFLE";
DamageType 'jolted';
RenderStyle "Add";
Radius 0.1;
Height 0;
Scale 0.4;
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
+NOTELEPORT;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
t = new("ShockBeamTracer");
t.owner = target;
t.ignore = self;
moving = true;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
if ( !moving ) return;
// step trace
tracedir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
t.Trace(pos,cursector,tracedir,1000,0);
totaldist += t.Results.Distance;
// spawn particles
for ( int i=0; i<t.Results.Distance; i+=80 )
Spawn("ShockBeamLight",Vec3Offset(tracedir.x*i,tracedir.y*i,tracedir.z*i));
for ( int i=0; i<t.Results.Distance; i+=2 )
{
Vector3 pofs = tracedir*FRandom[ASMD](0,2)+(FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5));
let s = Spawn("ShockSparkTrail",Vec3Offset(tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z));
s.vel = (FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03));
}
if ( totaldist >= 10000.0 )
{
// reposition and explode on air
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
ExplodeMissile(t.Results.HitLine,null);
moving = false;
let r = Spawn("ShockBeamRing",pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z);
}
else if ( t.Results.HitType == TRACE_HitNone )
{
// reposition
SetOrigin(t.Results.HitPos+t.Results.HitVector,true);
angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
pitch = asin(-t.Results.HitVector.z);
}
else if ( t.Results.HitType == TRACE_HitActor )
{
// reposition and explode on actor
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
ExplodeMissile(null,t.Results.HitActor);
if ( t.Results.HitActor is 'ShockHitbox' )
{
if ( target )
{
target.TakeInventory('ShockAmmo',2);
UTMainHandler.DoSwing(target,(FRandom[ASMD](-0.1,-0.6),FRandom[ASMD](-0.1,0.5)),5,-1,3,SWING_Spring,3,6);
}
let b = t.Results.HitActor.target;
UTMainHandler.DoBlast(b,250,70000);
b.ExplodeMissile(null,self);
b.A_Explode(165,250);
b.A_QuakeEx(6,6,6,60,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:250,rollIntensity:0.2);
b.A_SprayDecal("BigShockMark1",100);
b.A_SprayDecal("BigShockMark2",100);
Spawn("ShockRifleWave",b.pos);
Spawn("ShockBlastLight",b.pos);
let r = Spawn("ShockBlastRing",b.pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z);
A_PlaySound("shock/blast",CHAN_WEAPON,attenuation:0.5,pitch:0.6);
int numpt = Random[ASMD](200,300);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](1,32);
let s = Spawn("ShockSpark",b.pos);
s.vel = pvel;
}
}
else
{
t.Results.HitActor.DamageMobj(self,target,40,'jolted',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
UTMainHandler.DoKnockback(t.Results.HitActor,t.Results.HitVector,60000);
let r = Spawn("ShockBeamRing",pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z);
}
moving = false;
}
else
{
// reposition and explode on wall
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
A_SprayDecal("ShockMark",16);
ExplodeMissile(t.Results.HitLine,null);
moving = false;
Vector3 HitNormal = t.Results.HitVector;
if ( t.Results.HitType == TRACE_HitWall )
{
t.Results.HitLine.RemoteActivate(target,t.Results.Side,SPAC_Impact,pos);
// calculate normal
HitNormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
if ( t.Results.Side == 0 ) HitNormal *= -1;
}
else if ( t.Results.HitType == TRACE_HitFloor )
{
if ( t.Results.ffloor ) HitNormal = -t.Results.ffloor.top.Normal;
else HitNormal = t.Results.HitSector.floorplane.Normal;
}
else if ( t.Results.HitType == TRACE_HitCeiling )
{
if ( t.Results.ffloor ) HitNormal = -t.Results.ffloor.bottom.Normal;
else HitNormal = t.Results.HitSector.ceilingplane.Normal;
}
let r = Spawn("ShockBeamRing",pos);
r.angle = atan2(HitNormal.y,HitNormal.x);
r.pitch = asin(-HitNormal.z);
}
}
action void A_BeamExplode()
{
Spawn("ShockBeamLight",pos);
A_QuakeEx(2,2,2,5,0,120,"",QF_RELATIVE|QF_SCALEDOWN,falloff:60,rollIntensity:0.1);
A_PlaySound("shock/hit",CHAN_VOICE);
A_AlertMonsters();
int numpt = Random[ASMD](20,50);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,12);
let s = Spawn("ShockSpark",pos);
s.vel = pvel;
}
}
States
{
Spawn:
TNT1 A 1;
Wait;
Death:
TNT1 A 0 A_BeamExplode();
ASMX ABCDEFGHIJKL 1 Bright;
TNT1 A 100;
Stop;
}
}
Class SuperShockSpark : Actor
{
Default
{
RenderStyle "Add";
Radius 2;
Height 2;
+NOBLOCKMAP;
+NOGRAVITY;
+MISSILE;
+FORCEXYBILLBOARD;
+THRUACTORS;
+ROLLSPRITE;
+ROLLCENTER;
+NOTELEPORT;
+DONTSPLASH;
+CANBOUNCEWATER;
-BOUNCEAUTOOFF;
BounceType "Doom";
BounceFactor 1.0;
WallBounceFactor 1.0;
Scale 0.1;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( !bAMBUSH )
{
roll = FRandom[ASMD](0,360);
let s = Spawn(GetClass(),pos);
s.bAMBUSH = true;
s.vel = vel;
s.scale = scale;
s.roll = roll;
}
}
States
{
Spawn:
SSMK A 1 Bright
{
A_FadeOut(FRandom[ASMD](0.0,0.1));
vel *= 0.98;
}
Wait;
}
}
Class SuperShockSparkTrail : ShockSpark
{
Default
{
+AMBUSH;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
roll = FRandom[ASMD](0,360);
}
States
{
Spawn:
SSMK A 1 Bright A_FadeOut(FRandom[ASMD](0.0,0.2));
Wait;
}
}
Class SuperShockBeam : Actor
{
ShockBeamTracer t;
Vector3 tracedir;
bool moving;
double totaldist;
Default
{
Obituary "$O_SSHOCKRIFLE";
DamageType 'joltedX';
RenderStyle "Add";
Radius 0.1;
Height 0;
Scale 0.7;
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+FORCERADIUSDMG;
+EXTREMEDEATH;
+NODAMAGETHRUST;
+NOTELEPORT;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
t = new("ShockBeamTracer");
t.owner = target;
t.ignore = self;
moving = true;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
if ( !moving ) return;
// step trace
tracedir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
t.Trace(pos,cursector,tracedir,2000,0);
totaldist += t.Results.Distance;
// spawn particles
for ( int i=0; i<t.Results.Distance; i+=80 )
Spawn("SuperShockBeamLight",Vec3Offset(tracedir.x*i,tracedir.y*i,tracedir.z*i));
for ( int i=0; i<t.Results.Distance; i++ )
{
Vector3 pofs = tracedir*FRandom[ASMD](0,2)+(FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5));
let s = Spawn("SuperShockSparkTrail",Vec3Offset(tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z));
s.vel = (FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03));
}
if ( totaldist >= 10000.0 )
{
// reposition and explode on air
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
ExplodeMissile(t.Results.HitLine,null);
moving = false;
let r = Spawn("SuperShockBeamRing",pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z);
}
else if ( t.Results.HitType == TRACE_HitNone )
{
// reposition
SetOrigin(t.Results.HitPos+t.Results.HitVector,true);
angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
pitch = asin(-t.Results.HitVector.z);
}
else if ( t.Results.HitType == TRACE_HitActor )
{
// reposition and explode on actor
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
ExplodeMissile(null,t.Results.HitActor);
if ( t.Results.HitActor is 'ShockHitbox' )
{
if ( target )
{
target.TakeInventory('EnhancedShockAmmo',1);
UTMainHandler.DoSwing(target,(FRandom[ASMD](-0.1,-0.6),FRandom[ASMD](-0.1,0.5)),10,-2,3,SWING_Spring,3,6);
}
let b = t.Results.HitActor.target;
UTMainHandler.DoBlast(b,400,70000);
b.ExplodeMissile(null,self);
b.A_Explode(int.max,400);
b.A_QuakeEx(9,9,9,60,0,2400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:400,rollIntensity:0.4);
b.A_SprayDecal("BigShockMark1",100);
b.A_SprayDecal("SBigShockMark2",100);
Spawn("SuperShockRifleWave",b.pos);
Spawn("SuperShockBlastLight",b.pos);
let r = Spawn("SuperShockBlastRing",b.pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z);
A_PlaySound("shock/blast",CHAN_WEAPON,attenuation:0.5,pitch:0.6);
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
int numpt = Random[ASMD](200,300);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](2,64);
let s = Spawn("SuperShockSpark",b.pos);
s.vel = pvel;
}
}
else
{
// the actor may "cease to exist" if it dies after the call to ExplodeMissile, so guard against that
if ( t.Results.HitActor )
{
// damage was 1000 in UT but it's meant to be instakill and players couldn't reach that health legitimately anyway, so rather than
// some absurd number they settled for that
// we ain't goin' that way here
t.Results.HitActor.DamageMobj(self,target,int.max,'joltedX',DMG_USEANGLE|DMG_THRUSTLESS,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
UTMainHandler.DoKnockback(t.Results.HitActor,t.Results.HitVector,60000);
}
let r = Spawn("SuperShockBeamRing",pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z);
}
t.lasthit = t.Results.HitActor;
}
else
{
// reposition and explode on wall
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
A_SprayDecal("ShockMark",16);
ExplodeMissile(t.Results.HitLine,null);
moving = false;
Vector3 HitNormal = t.Results.HitVector;
if ( t.Results.HitType == TRACE_HitWall )
{
t.Results.HitLine.RemoteActivate(target,t.Results.Side,SPAC_Impact,pos);
// calculate normal
HitNormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
if ( t.Results.Side == 1 ) HitNormal *= -1;
}
else if ( t.Results.HitType == TRACE_HitFloor )
{
if ( t.Results.ffloor ) HitNormal = -t.Results.ffloor.top.Normal;
else HitNormal = t.Results.HitSector.floorplane.Normal;
}
else if ( t.Results.HitType == TRACE_HitCeiling )
{
if ( t.Results.ffloor ) HitNormal = -t.Results.ffloor.bottom.Normal;
else HitNormal = t.Results.HitSector.ceilingplane.Normal;
}
let r = Spawn("SuperShockBeamRing",pos);
r.angle = atan2(HitNormal.y,HitNormal.x);
r.pitch = asin(-HitNormal.z);
}
}
action void A_BeamExplode()
{
Spawn("SuperShockBeamLight",pos);
if ( !flak_classicsshock )
{
UTMainHandler.DoBlast(self,50,60000);
A_Explode(int.max,50);
}
A_QuakeEx(6,6,6,5,0,100,"",QF_RELATIVE|QF_SCALEDOWN,falloff:50,rollIntensity:0.2);
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
A_AlertMonsters();
int numpt = Random[ASMD](20,50);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,24);
let s = Spawn("SuperShockSpark",pos);
s.vel = pvel;
}
}
States
{
Spawn:
TNT1 A 1;
Wait;
Death:
TNT1 A 0 A_BeamExplode();
SSMX ABCDEFGHIJKL 1 Bright;
TNT1 A 100;
Stop;
}
}
Class ShockBallLight : DynamicLight
{
Default
{
DynamicLight.Type "Point";
Args 160,128,255,120;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
}
override void Tick()
{
Super.Tick();
if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
args[LIGHT_INTENSITY] = Random[ASMD](10,14)*10;
}
}
Class SuperShockBallLight : ShockBallLight
{
Default
{
Args 255,160,128,120;
}
}
Class ShockBeamLight : PaletteLight
{
Default
{
Tag "ExplShock";
ReactionTime 15;
Args 0,0,0,80;
+DYNAMICLIGHT.ATTENUATE;
}
}
Class SuperShockBeamLight : PaletteLight
{
Default
{
Tag "ExplSShock";
ReactionTime 15;
Args 0,0,0,100;
+DYNAMICLIGHT.ATTENUATE;
}
}
Class ShockBeamHitLight : PaletteLight
{
Default
{
Tag "ExplShock";
ReactionTime 24;
Args 0,0,0,120;
}
}
Class SuperShockBeamHitLight : PaletteLight
{
Default
{
Tag "ExplSShock";
ReactionTime 24;
Args 0,0,0,150;
}
}
Class ShockBlastLight : PaletteLight
{
Default
{
Tag "ExplShock";
ReactionTime 60;
Args 0,0,0,300;
}
}
Class SuperShockBlastLight : PaletteLight
{
Default
{
Tag "ExplSShock";
ReactionTime 60;
Args 0,0,0,400;
}
}
Class ShockExplLight : PaletteLight
{
Default
{
Tag "ExplShock";
ReactionTime 30;
Args 0,0,0,150;
}
}
Class SuperShockExplLight : PaletteLight
{
Default
{
Tag "ExplSShock";
ReactionTime 30;
Args 0,0,0,200;
}
}
Class ShockHitbox : Actor
{
Default
{
Radius 8;
Height 16;
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+NOTELEPORT;
}
override void Tick()
{
Super.Tick();
if ( !target || !target.InStateSequence(target.CurState,target.FindState("Spawn")) )
{
Destroy();
return;
}
SetOrigin(target.Vec3Offset(0,0,-height*0.5),true);
}
override bool CanCollideWith( Actor other, bool passive )
{
return false;
}
}
Class ShockBall : Actor
{
Actor l, b;
override void PostBeginPlay()
{
Super.PostBeginPlay();
l = Spawn("ShockBallLight",pos);
l.target = self;
b = Spawn("ShockHitbox",pos);
b.target = self;
}
action void A_BallExplode()
{
UTMainHandler.DoBlast(self,70,70000);
A_Explode(55,70);
A_SprayDecal("ShockMarkBig",16);
Spawn("ShockExplLight",pos);
A_SetScale(1.0);
let r = Spawn("ShockBeamRing",pos);
Vector3 HitNormal = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
if ( BlockingLine ) HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
else if ( BlockingFloor )
{
// find closest 3d floor for its normal
F3DFloor ff = null;
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
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;
r.SetOrigin(r.Vec3Offset(0,0,2),false);
}
else if ( BlockingCeiling )
{
// find closest 3d floor for its normal
F3DFloor ff = null;
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
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;
}
r.angle = atan2(HitNormal.y,HitNormal.x);
r.pitch = asin(-HitNormal.z);
r.scale *= 1.5;
A_PlaySound("shock/hit",CHAN_VOICE);
A_PlaySound("shock/ball",CHAN_WEAPON,pitch:FRandom[ASMD](0.5,1.5));
A_QuakeEx(4,4,4,30,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:70,rollIntensity:0.15);
A_AlertMonsters();
int numpt = Random[ASMD](50,100);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,12);
let s = Spawn("ShockSpark",pos);
s.vel = pvel;
}
}
Default
{
Obituary "$O_SHOCKRIFLE";
RenderStyle "Add";
DamageType 'jolted';
Radius 2;
Height 2;
Scale 0.4;
Speed 20;
PROJECTILE;
+FORCEXYBILLBOARD;
+SKYEXPLODE;
+EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
}
States
{
Spawn:
ASMB ABCD 2 Bright;
Loop;
Death:
TNT1 A 0 A_BallExplode();
ASMX ABCDEFGHIJKL 2 Bright;
TNT1 A 300;
Stop;
}
}
Class SuperShockBall : Actor
{
Actor l, b;
override void PostBeginPlay()
{
Super.PostBeginPlay();
l = Spawn("SuperShockBallLight",pos);
l.target = self;
b = Spawn("ShockHitbox",pos);
b.target = self;
}
action void A_BallExplode()
{
UTMainHandler.DoBlast(self,120,70000);
A_Explode(int.max,120);
A_SprayDecal("ShockMarkBig",16);
Spawn("SuperShockExplLight",pos);
A_SetScale(1.5);
let r = Spawn("SuperShockBeamRing",pos);
Vector3 HitNormal = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
if ( BlockingLine ) HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
else if ( BlockingFloor )
{
// find closest 3d floor for its normal
F3DFloor ff = null;
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
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;
r.SetOrigin(r.Vec3Offset(0,0,2),false);
}
else if ( BlockingCeiling )
{
// find closest 3d floor for its normal
F3DFloor ff = null;
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
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;
}
r.angle = atan2(HitNormal.y,HitNormal.x);
r.pitch = asin(-HitNormal.z);
r.scale *= 1.5;
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
A_PlaySound("shock/ball",CHAN_WEAPON,attenuation:0.5,pitch:FRandom[ASMD](0.5,1.5));
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
A_QuakeEx(8,8,8,30,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollIntensity:0.25);
A_AlertMonsters();
int numpt = Random[ASMD](50,100);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,24);
let s = Spawn("SuperShockSpark",pos);
s.vel = pvel;
}
}
Default
{
Obituary "$O_SSHOCKRIFLE";
RenderStyle "Add";
DamageType 'joltedX';
Radius 2;
Height 2;
Scale 0.5;
Speed 24;
PROJECTILE;
+FORCEXYBILLBOARD;
+SKYEXPLODE;
+FORCERADIUSDMG;
+EXTREMEDEATH;
+EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
}
States
{
Spawn:
SSMB ABCD 2 Bright;
Loop;
Death:
TNT1 A 0 A_BallExplode();
SSMX ABCDEFGHIJKL 2 Bright;
TNT1 A 300;
Stop;
}
}
Class ViewShockSpark : ShockSpark
{
Vector3 ofs, vvel;
override void PostBeginPlay()
{
Actor.PostBeginPlay();
scale *= FRandom[Puff](0.4,0.9);
alpha *= FRandom[Puff](0.5,2.0);
roll = FRandom[ASMD](0,360);
}
override void Tick()
{
Actor.Tick();
if ( !target || !target.player )
{
Destroy();
return;
}
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(target.pitch,target.angle,target.roll);
Vector3 origin = x*ofs.x+y*ofs.y+z*ofs.z+(0,0,target.player.viewz);
SetOrigin(target.Vec2OffsetZ(origin.x,origin.y,origin.z),true);
bInvisible = (players[consoleplayer].camera != target);
if ( isFrozen() ) return;
ofs += vvel;
vvel *= 0.9;
scale *= 0.8;
if ( scale.x <= 0.01 ) Destroy();
}
States
{
Spawn:
ASMK A 1 Bright A_FadeOut(FRandom[ASMD](0.0,0.1));
Wait;
}
}
Class ShockRifle : UTWeapon
{
action void A_ShockFire()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
A_PlaySound("shock/fire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(128,128,0,255),1);
UTMainHandler.DoSwing(self,(FRandom[ASMD](-0.1,-0.6),FRandom[ASMD](-0.1,0.5)),2,-0.3,3,SWING_Spring,0,4);
A_AlertMonsters();
A_QuakeEx(2,2,2,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+2.0*y-1.5*z;
Actor p = Spawn("ShockBeam",origin);
p.angle = angle;
p.pitch = BulletSlope();
p.target = self;
for ( int i=0; i<12; i++ )
{
let s = Spawn("UTViewSmoke",origin);
UTViewSmoke(s).ofs = (10,2,-1.5);
s.scale *= 1.8;
s.target = self;
s.SetShade("C080FF");
s.A_SetRenderStyle(0.4,STYLE_AddShaded);
UTViewSmoke(s).vvel += (FRandom[ASMD](0.2,0.6),FRandom[ASMD](-0.2,0.2),FRandom[ASMD](-0.2,0.2));
}
int numpt = Random[ASMD](20,40);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("ViewShockSpark",origin);
ViewShockSpark(s).ofs = (10,2,-1.5);
s.target = self;
ViewShockSpark(s).vvel += (FRandom[ASMD](0.5,2.0),FRandom[ASMD](-1.5,1.5),FRandom[ASMD](-1.5,1.5));
}
}
action void A_ShockAlt()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
A_PlaySound("shock/altfire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(128,128,0,255),1);
UTMainHandler.DoSwing(self,(FRandom[ASMD](-0.1,-0.6),FRandom[ASMD](-0.1,0.5)),3,-0.4,3,SWING_Spring,0,4);
A_AlertMonsters();
A_QuakeEx(2,2,2,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+2.0*y-1.5*z;
Actor p = Spawn("ShockBall",origin);
p.angle = angle;
p.pitch = BulletSlope();
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
p.target = self;
for ( int i=0; i<12; i++ )
{
let s = Spawn("UTViewSmoke",origin);
UTViewSmoke(s).ofs = (10,2,-1.5);
s.scale *= 2.2;
s.target = self;
s.SetShade("C080FF");
s.A_SetRenderStyle(0.4,STYLE_AddShaded);
UTViewSmoke(s).vvel += (FRandom[ASMD](0.4,1.2),FRandom[ASMD](-0.4,0.4),FRandom[ASMD](-0.4,0.4));
}
int numpt = Random[ASMD](20,40);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("ViewShockSpark",origin);
ViewShockSpark(s).ofs = (10,2,-1.5);
s.target = self;
ViewShockSpark(s).vvel += (FRandom[ASMD](0.5,2.0),FRandom[ASMD](-1.5,1.5),FRandom[ASMD](-1.5,1.5));
}
}
Default
{
Tag "$T_SHOCKRIFLE";
Inventory.PickupMessage "$I_SHOCKRIFLE";
Weapon.UpSound "shock/select";
Weapon.SlotNumber 4;
Weapon.SelectionOrder 6;
Weapon.AmmoType "ShockAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "ShockAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 20;
UTWeapon.DropAmmo 5;
}
States
{
Spawn:
ASMP A -1;
Stop;
ASMP B -1;
Stop;
Ready:
ASMS ABCDEFGHIJKLMNO 1 A_WeaponReady(WRF_NOFIRE);
Idle:
ASMI A 1
{
A_CheckReload();
A_WeaponReady();
}
Wait;
Fire:
ASMF A 1 A_ShockFire();
ASMF BCDEFGHIJJ 2;
Goto Idle;
AltFire:
ASMA A 1 A_ShockAlt();
ASMA BCDFGHIJ 2;
Goto Idle;
Deselect:
ASMD ABCDEFG 1;
ASMD G 1 A_Lower(int.max);
Wait;
Select:
ASMS A 1 A_Raise(int.max);
Wait;
}
}
Class EnhancedShockAmmo : Ammo
{
int ticcnt;
override void Tick()
{
Super.Tick();
if ( !Owner ) return;
ticcnt++;
if ( deathmatch && flak_instagib )
{
if ( ticcnt < 35 ) return;
ticcnt = 0;
if ( Amount < MaxAmount ) Amount++;
}
else
{
if ( ticcnt < 105 ) return;
ticcnt = 0;
if ( Amount > 0 ) Amount--;
}
}
Default
{
Tag "$T_SSHOCKAMMO";
Inventory.PickupMessage "$I_SSHOCKAMMO";
Inventory.Amount 5;
Inventory.MaxAmount 50;
Ammo.BackpackAmount 0;
Ammo.BackpackMaxAmount 50;
Ammo.DropAmount 2;
}
States
{
Spawn:
SHOA A -1;
Stop;
}
}
Class ViewSuperShockSpark : ViewShockSpark
{
States
{
Spawn:
SSMK A 1 Bright A_FadeOut(FRandom[ASMD](0.0,0.1));
Wait;
}
}
Class EnhancedShockRifle : UTWeapon
{
override void PostBeginPlay()
{
Super.PostBeginPlay();
}
action void A_SShockFire()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
A_PlaySound("shock/fire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(128,255,128,0),1);
UTMainHandler.DoSwing(self,(FRandom[ASMD](-0.1,-0.6),FRandom[ASMD](-0.1,0.5)),4,-0.6,3,SWING_Spring,0,4);
A_AlertMonsters();
A_QuakeEx(3,3,3,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.15);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+2.0*y-1.5*z;
Actor p = Spawn("SuperShockBeam",origin);
p.angle = angle;
p.pitch = BulletSlope();
p.target = self;
for ( int i=0; i<12; i++ )
{
let s = Spawn("UTViewSmoke",origin);
UTViewSmoke(s).ofs = (10,2,-1.5);
s.scale *= 1.8;
s.target = self;
s.SetShade("FFC040");
s.A_SetRenderStyle(0.4,STYLE_AddShaded);
UTViewSmoke(s).vvel += (FRandom[ASMD](0.2,0.6),FRandom[ASMD](-0.2,0.2),FRandom[ASMD](-0.2,0.2));
}
int numpt = Random[ASMD](20,40);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("ViewSuperShockSpark",origin);
ViewShockSpark(s).ofs = (10,2,-1.5);
s.target = self;
ViewShockSpark(s).vvel += (FRandom[ASMD](0.5,2.0),FRandom[ASMD](-1.5,1.5),FRandom[ASMD](-1.5,1.5));
}
}
action void A_SShockAlt()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
A_PlaySound("shock/altfire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(128,255,128,0),1);
UTMainHandler.DoSwing(self,(FRandom[ASMD](-0.1,-0.6),FRandom[ASMD](-0.1,0.5)),6,-0.8,3,SWING_Spring,0,4);
A_AlertMonsters();
A_QuakeEx(3,3,3,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.15);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+2.0*y-1.5*z;
Actor p = Spawn("SuperShockBall",origin);
p.angle = angle;
p.pitch = BulletSlope();
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
p.target = self;
for ( int i=0; i<12; i++ )
{
let s = Spawn("UTViewSmoke",origin);
UTViewSmoke(s).ofs = (10,2,-1.5);
s.scale *= 2.2;
s.target = self;
s.SetShade("FFC040");
s.A_SetRenderStyle(0.4,STYLE_AddShaded);
UTViewSmoke(s).vvel += (FRandom[ASMD](0.4,1.2),FRandom[ASMD](-0.4,0.4),FRandom[ASMD](-0.4,0.4));
}
int numpt = Random[ASMD](20,40);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("ViewSuperShockSpark",origin);
ViewShockSpark(s).ofs = (10,2,-1.5);
s.target = self;
ViewShockSpark(s).vvel += (FRandom[ASMD](0.5,2.0),FRandom[ASMD](-1.5,1.5),FRandom[ASMD](-1.5,1.5));
}
}
override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount )
{
if ( (Owner.player.ReadyWeapon != self) && (Ammo1.Amount <= 0) ) return false;
return Super.CheckAmmo(fireMode,autoSwitch,requireAmmo,ammocount);
}
Default
{
Tag "$T_SSHOCKRIFLE";
Inventory.PickupMessage "$I_SSHOCKRIFLE";
Weapon.UpSound "shock/select";
Weapon.SlotNumber 4;
Weapon.SelectionOrder 6;
+INVENTORY.ALWAYSPICKUP;
Weapon.AmmoType "EnhancedShockAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "EnhancedShockAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 50;
UTWeapon.DropAmmo 5;
+WEAPON.AMMO_OPTIONAL;
+WEAPON.ALT_AMMO_OPTIONAL;
+WEAPON.CHEATNOTWEAPON;
+INVENTORY.IGNORESKILL;
}
States
{
Spawn:
ASMP A -1;
Stop;
ASMP B -1;
Stop;
Ready:
ASMS ABCDEFGHIJKLMNO 1 A_WeaponReady(WRF_NOFIRE);
Idle:
ASMI A 1 A_WeaponReady();
Wait;
Fire:
ASMI A 0 A_JumpIfNoAmmo("DryFire");
ASMF A 1 A_SShockFire();
ASMF BCDEFGHIJJ 2;
Goto Idle;
AltFire:
ASMI A 0 A_JumpIf(flak_classicsshock,"Fire");
ASMI A 0 A_JumpIfNoAmmo("DryFire");
ASMA A 1 A_SShockAlt();
ASMA BCDFGHIJ 2;
Goto Idle;
DryFire:
ASMA I 3
{
A_PlaySound("sshock/dryfire",CHAN_WEAPON);
A_AlertMonsters();
}
ASMA J 4;
ASMI A 10;
Goto Idle;
Deselect:
ASMD ABCDEFG 1;
ASMD G 1 A_Lower(int.max);
Wait;
Select:
ASMS A 1 A_Raise(int.max);
Wait;
}
}