flak_m/zscript/shockrifle.zsc
Marisa Kirisame fb96c7523e Portal awareness adjustments to various vector operations.
Got rid of the deprecated Matrix4.GetAxes method. Next step is to get rid of more stuff by migrating to libeye.
Mirrored Translocator model so it shows the actually detailed side. At some point in UT's development it got flipped around for some reason.
Weapon code cleanup (most noticeable on states).
Backported scope shader from Doomreal.
Added optional "dummied out" Sniper zoom sounds from a dubious source.
2019-09-28 20:06:51 +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 = level.Vec3Offset(target.Vec2OffsetZ(0,0,target.player.viewz),x*ofs.x+y*ofs.y+z*ofs.z);
SetOrigin(origin,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 = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*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 = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*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 = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*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 = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*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;
}
}