1653 lines
50 KiB
Text
1653 lines
50 KiB
Text
// Blackmann-Forx Silver Bullet JET (successor to Silver Bullet from Zanaveth Ultra Suite)
|
|
// Slot 8, replaces Plasma Rifle, Hellstaff, Quietus (hilt)
|
|
|
|
Class SilverBulletCasing : SWWMCasing
|
|
{
|
|
Default
|
|
{
|
|
BounceSound "silverbullet/casing";
|
|
}
|
|
}
|
|
Class SilverBulletCasing2 : SilverBulletCasing {}
|
|
|
|
Class SilverBulletMag : SWWMCasing
|
|
{
|
|
Default
|
|
{
|
|
Mass 10;
|
|
BounceFactor 0.4;
|
|
WallBounceFactor 0.4;
|
|
BounceSound "silverbullet/mag";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
heat = 0;
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
XZW1 BC -1
|
|
{
|
|
pitch = roll = 0;
|
|
angle = FRandom[Junk](0,360);
|
|
frame = RandomPick[Junk](1,2);
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
Class SilverBulletMag2 : SilverBulletMag {}
|
|
|
|
Class SilverAirRip : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SILVERBULLET";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
SWWMUtility.DoExplosion(self,40,2000,40,ignoreme:target);
|
|
Destroy();
|
|
}
|
|
}
|
|
Class SilverAirRip2 : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SILVERBULLET2";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
SWWMUtility.DoExplosion(self,20,2000,30,ignoreme:target);
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
Class SilverImpact : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SILVERBULLET";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
SWWMUtility.DoExplosion(self,100,8000,100,20);
|
|
A_AlertMonsters(swwm_uncapalert?0:2500);
|
|
A_QuakeEx(4,4,4,20,0,400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.9);
|
|
if ( special1 )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
A_StartSound("silverbullet/hit",CHAN_VOICE,CHANF_DEFAULT,1.,.7);
|
|
A_SprayDecal("BigPock",-64);
|
|
A_SprayDecal("HugeWallCrack",-64);
|
|
int numpt = Random[Silverbullet](15,25);
|
|
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Silverbullet](-.4,.4),FRandom[Silverbullet](-.4,.4),FRandom[Silverbullet](-.4,.4))).unit()*FRandom[Silverbullet](.4,2.);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.scale *= 1.8;
|
|
s.special1 = Random[Silverbullet](1,3);
|
|
s.SetShade(Color(1,1,1)*Random[Silverbullet](96,192));
|
|
}
|
|
numpt = Random[Silverbullet](6,9);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Silverbullet](-1,1),FRandom[Silverbullet](-1,1),FRandom[Silverbullet](-1,1)).unit()*FRandom[Silverbullet](2,8);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.scale *= 1.3;
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Silverbullet](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Silverbullet](-.6,.6),FRandom[Silverbullet](-.6,.6),FRandom[Silverbullet](-.6,.6))).unit()*FRandom[Silverbullet](6,20);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.scale *= 1.6;
|
|
s.vel = pvel;
|
|
}
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 20;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class WallPenetrate
|
|
{
|
|
Vector3 hitpos, hitdir, hitnormal, bustdir;
|
|
int hitside, hittier, hittype, penetration;
|
|
Line hitline;
|
|
Sector hitsector;
|
|
F3DFloor hitffloor;
|
|
}
|
|
|
|
Class AuxiliarySilverBulletTracer : LineTracer
|
|
{
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
if ( Results.HitType == TRACE_HitActor ) 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 SilverBulletTracer : SpreadSlugTracer
|
|
{
|
|
Array<WallPenetrate> WallPenetrateList;
|
|
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
// liquid splashes
|
|
if ( Results.CrossedWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.sect = Results.CrossedWater;
|
|
hl.hitpos = Results.CrossedWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
else if ( Results.Crossed3DWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.sect = Results.Crossed3DWater;
|
|
hl.hitpos = Results.Crossed3DWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
if ( Results.HitType == TRACE_HitActor )
|
|
{
|
|
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
|
if ( Results.HitActor.bSHOOTABLE )
|
|
{
|
|
let ent = new("HitListEntry");
|
|
ent.hitactor = Results.HitActor;
|
|
ent.hitlocation = Results.HitPos;
|
|
ent.x = Results.HitVector;
|
|
if ( (Results.HitActor.Health >= int(penetration)) || Results.HitActor.bNODAMAGE )
|
|
{
|
|
ent.hitdamage = int(penetration);
|
|
penetration = 0;
|
|
}
|
|
else
|
|
{
|
|
ent.hitdamage = min(Results.HitActor.health+int(Results.HitActor.GetSpawnHealth()*gameinfo.gibfactor),int(penetration));
|
|
int killdamage = min(Results.HitActor.health,int(penetration));
|
|
penetration = max(0,penetration-killdamage*.4);
|
|
}
|
|
hitlist.Push(ent);
|
|
if ( penetration <= 0 ) return TRACE_Stop;
|
|
return TRACE_Skip;
|
|
}
|
|
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)) )
|
|
{
|
|
for ( int i=1; i<int(penetration/12); i++ )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(Results.HitPos,Results.HitVector*i);
|
|
if ( level.IsPointInLevel(ofs) )
|
|
{
|
|
let wp = new("WallPenetrate");
|
|
wp.hittype = Results.HitType;
|
|
wp.hitline = Results.HitLine;
|
|
wp.hitside = Results.Side;
|
|
wp.hittier = Results.Tier;
|
|
wp.hitsector = Results.HitSector;
|
|
wp.hitffloor = Results.ffloor;
|
|
wp.hitpos = Results.HitPos;
|
|
wp.hitdir = Results.HitVector;
|
|
wp.bustdir = Results.HitVector;
|
|
wp.penetration = int(penetration);
|
|
wp.hitnormal = (-Results.HitLine.delta.y,Results.HitLine.delta.x,0).unit();
|
|
if ( !Results.Side ) wp.hitnormal *= -1;
|
|
WallPenetrateList.Push(wp);
|
|
penetration = max(0,penetration-i*4);
|
|
// trace backwards to find exit surface
|
|
let at = new("AuxiliarySilverBulletTracer");
|
|
at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_NoSky);
|
|
if ( at.Results.HitType != TRACE_HitNone )
|
|
{
|
|
let wp2 = new("WallPenetrate");
|
|
wp2.hittype = at.Results.HitType;
|
|
wp2.hitline = at.Results.HitLine;
|
|
wp2.hitside = at.Results.Side;
|
|
wp2.hittier = at.Results.Tier;
|
|
wp2.hitsector = at.Results.HitSector;
|
|
wp2.hitffloor = at.Results.ffloor;
|
|
wp2.hitside = at.Results.Side;
|
|
wp2.hitpos = at.Results.HitPos;
|
|
wp2.hitdir = at.Results.HitVector;
|
|
wp2.bustdir = -at.Results.HitVector;
|
|
wp2.penetration = int(penetration);
|
|
if ( at.Results.HitType == TRACE_HitWall )
|
|
{
|
|
wp2.hitnormal = (-at.Results.HitLine.delta.y,at.Results.HitLine.delta.x,0).unit();
|
|
if ( !at.Results.Side ) wp2.hitnormal *= -1;
|
|
if ( at.Results.HitLine.sidedef[1] )
|
|
ShootThroughList.Push(at.Results.HitLine);
|
|
}
|
|
else if ( at.Results.HitType == TRACE_HitCeiling )
|
|
wp2.hitnormal = at.Results.HitSector.ceilingplane.Normal;
|
|
else if ( at.Results.HitType == TRACE_HitFloor )
|
|
wp2.hitnormal = at.Results.HitSector.floorplane.Normal;
|
|
WallPenetrateList.Push(wp2);
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
}
|
|
return TRACE_Stop;
|
|
}
|
|
ShootThroughList.Push(Results.HitLine);
|
|
return TRACE_Skip;
|
|
}
|
|
else if ( Results.HitType != TRACE_HitNone )
|
|
{
|
|
for ( int i=1; i<int(penetration/12); i++ )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(Results.HitPos,Results.HitVector*i);
|
|
if ( level.IsPointInLevel(ofs) )
|
|
{
|
|
let wp = new("WallPenetrate");
|
|
wp.hittype = Results.HitType;
|
|
wp.hitline = Results.HitLine;
|
|
wp.hitside = Results.Side;
|
|
wp.hittier = Results.Tier;
|
|
wp.hitsector = Results.HitSector;
|
|
wp.hitffloor = Results.ffloor;
|
|
wp.hitpos = Results.HitPos;
|
|
wp.hitdir = Results.HitVector;
|
|
wp.bustdir = Results.HitVector;
|
|
wp.penetration = int(penetration);
|
|
if ( Results.HitType == TRACE_HitWall )
|
|
{
|
|
wp.hitnormal = (-Results.HitLine.delta.y,Results.HitLine.delta.x,0).unit();
|
|
if ( !Results.Side ) wp.hitnormal *= -1;
|
|
ShootThroughList.Push(Results.HitLine);
|
|
}
|
|
else if ( Results.HitType == TRACE_HitCeiling )
|
|
wp.hitnormal = Results.HitSector.ceilingplane.Normal;
|
|
else if ( Results.HitType == TRACE_HitFloor )
|
|
wp.hitnormal = Results.HitSector.floorplane.Normal;
|
|
WallPenetrateList.Push(wp);
|
|
penetration = max(0,penetration-i*4);
|
|
// trace backwards to find exit surface
|
|
let at = new("AuxiliarySilverBulletTracer");
|
|
at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_NoSky);
|
|
if ( at.Results.HitType != TRACE_HitNone )
|
|
{
|
|
let wp2 = new("WallPenetrate");
|
|
wp2.hittype = at.Results.HitType;
|
|
wp2.hitline = at.Results.HitLine;
|
|
wp2.hitside = at.Results.Side;
|
|
wp2.hittier = at.Results.Tier;
|
|
wp2.hitsector = at.Results.HitSector;
|
|
wp2.hitffloor = at.Results.ffloor;
|
|
wp2.hitside = at.Results.Side;
|
|
wp2.hitpos = at.Results.HitPos;
|
|
wp2.hitdir = at.Results.HitVector;
|
|
wp2.bustdir = -at.Results.HitVector;
|
|
wp2.penetration = int(penetration);
|
|
if ( at.Results.HitType == TRACE_HitWall )
|
|
{
|
|
wp2.hitnormal = (-at.Results.HitLine.delta.y,at.Results.HitLine.delta.x,0).unit();
|
|
if ( !at.Results.Side ) wp2.hitnormal *= -1;
|
|
if ( at.Results.HitLine.sidedef[1] )
|
|
ShootThroughList.Push(at.Results.HitLine);
|
|
}
|
|
else if ( at.Results.HitType == TRACE_HitCeiling )
|
|
wp2.hitnormal = at.Results.HitSector.ceilingplane.Normal;
|
|
else if ( at.Results.HitType == TRACE_HitFloor )
|
|
wp2.hitnormal = at.Results.HitSector.floorplane.Normal;
|
|
WallPenetrateList.Push(wp2);
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
}
|
|
}
|
|
return TRACE_Stop;
|
|
}
|
|
}
|
|
|
|
Class FatChodeTracer : LineTracer
|
|
{
|
|
Actor ignoreme;
|
|
Array<Line> ShootThroughList;
|
|
Array<WaterHit> WaterHitList;
|
|
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
// liquid splashes
|
|
if ( Results.CrossedWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.sect = Results.CrossedWater;
|
|
hl.hitpos = Results.CrossedWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
else if ( Results.Crossed3DWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.sect = Results.Crossed3DWater;
|
|
hl.hitpos = Results.Crossed3DWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
if ( Results.HitType == TRACE_HitActor )
|
|
{
|
|
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
|
if ( Results.HitActor.bSHOOTABLE ) 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) )
|
|
return TRACE_Stop;
|
|
ShootThroughList.Push(Results.HitLine);
|
|
return TRACE_Skip;
|
|
}
|
|
return TRACE_Stop;
|
|
}
|
|
}
|
|
|
|
Class ExploLight3 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
ReactionTime 30;
|
|
Args 0,0,0,250;
|
|
}
|
|
}
|
|
Class FatChodeImpact : Actor
|
|
{
|
|
double realangle, realpitch;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_SILVERBULLET2";
|
|
DamageType 'Explodium';
|
|
RenderStyle "Add";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale 4.5;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
SWWMUtility.DoExplosion(self,1500,40000,250,120,DE_THRUWALLS|DE_EXTRAZTHRUST);
|
|
A_AlertMonsters(swwm_uncapalert?0:8000);
|
|
A_QuakeEx(7,7,7,50,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.);
|
|
A_StartSound("silverbullet/chode",CHAN_VOICE,CHANF_DEFAULT,1.,.35);
|
|
A_SprayDecal("BigPock",-64);
|
|
A_SprayDecal("HugeWallCrack",-64);
|
|
A_SprayDecal("WumboRocketBlast",-64);
|
|
Scale *= FRandom[ExploS](0.8,1.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[Silverbullet](15,25);
|
|
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Silverbullet](-.4,.4),FRandom[Silverbullet](-.4,.4),FRandom[Silverbullet](-.4,.4))).unit()*FRandom[Silverbullet](.4,2.);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.scale *= 1.8;
|
|
s.special1 = Random[Silverbullet](1,4);
|
|
s.SetShade(Color(1,1,1)*Random[Silverbullet](96,192));
|
|
}
|
|
numpt = Random[Silverbullet](6,9);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Silverbullet](-1,1),FRandom[Silverbullet](-1,1),FRandom[Silverbullet](-1,1)).unit()*FRandom[Silverbullet](2,8);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.scale *= 1.3;
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Silverbullet](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Silverbullet](-.6,.6),FRandom[Silverbullet](-.6,.6),FRandom[Silverbullet](-.6,.6))).unit()*FRandom[Silverbullet](6,20);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.scale *= 1.6;
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Silverbullet](16,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("FatChodeExtraArm",pos);
|
|
s.target = target;
|
|
}
|
|
numpt = Random[Silverbullet](8,10);
|
|
Vector3 y, z, dir;
|
|
double a, s;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(realpitch,realangle,0);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let e = Spawn("FatChodeExplosionArm",pos);
|
|
e.target = target;
|
|
a = FRandom[Silverbullet](0,360);
|
|
s = FRandom[Silverbullet](0,.2);
|
|
dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
|
|
e.angle = atan2(dir.y,dir.x);
|
|
e.pitch = asin(-dir.z);
|
|
}
|
|
Spawn("ExploLight3",pos);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\ 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class FatChodeExtraArm : ExplodiumMagArm
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SILVERBULLET2";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
vel *= 1.5;
|
|
}
|
|
}
|
|
|
|
Class FatChodeExplosionTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale 3.;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX1 ACEGIKMOQSUWY[ 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class FatChodeExplosionArm : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_SILVERBULLET2";
|
|
DamageType 'Explodium';
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+NOBLOCKMAP;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
reactiontime = Random[ExploS](15,20);
|
|
vel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch))*FRandom[ExploS](20.,30.);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1
|
|
{
|
|
A_CountDown();
|
|
SWWMUtility.DoExplosion(self,20+reactiontime,8000+1500*reactiontime,80+5*reactiontime,50,DE_THRUWALLS);
|
|
if ( level.IsPointInLevel(pos) )
|
|
{
|
|
A_SprayDecal("HugeRocketBlast",-32);
|
|
Spawn("FatChodeExplosionTrail",pos);
|
|
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(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,4);
|
|
s.scale *= 2.4;
|
|
s.alpha *= .1+.4*(ReactionTime/15.);
|
|
}
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class SilverBullet : SWWMWeapon
|
|
{
|
|
bool chambered, fired;
|
|
bool fcbchambered, fcbloaded, fcbselected;
|
|
int clipcount;
|
|
|
|
transient ui TextureID WeaponBox[2], ZoomBar, BulletIcon[2], AmmoIcon[2];
|
|
transient ui Font TewiFont;
|
|
transient ui DynamicValueInterpolator ZoomInter;
|
|
|
|
bool zoomed;
|
|
double zoomlevel;
|
|
ui TextureID reticle, scope;
|
|
transient ui CVar useshaders;
|
|
int rezoom;
|
|
bool proneme;
|
|
|
|
State dezoomstate;
|
|
|
|
Property ClipCount : clipcount;
|
|
|
|
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
|
{
|
|
if ( fcbchambered ) return StringTable.Localize("$O_SILVERBULLET2");
|
|
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
|
}
|
|
|
|
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
|
|
{
|
|
if ( !WeaponBox[0] ) WeaponBox[0] = TexMan.CheckForTexture("graphics/HUD/SilverBulletDisplay.png",TexMan.Type_Any);
|
|
if ( !WeaponBox[1] ) WeaponBox[1] = TexMan.CheckForTexture("graphics/HUD/SilverBulletZoomDisplay.png",TexMan.Type_Any);
|
|
if ( !BulletIcon[0] ) BulletIcon[0] = TexMan.CheckForTexture("graphics/HUD/SilverBulletXSB.png",TexMan.Type_Any);
|
|
if ( !BulletIcon[1] ) BulletIcon[1] = TexMan.CheckForTexture("graphics/HUD/SilverBulletFCB.png",TexMan.Type_Any);
|
|
if ( !AmmoIcon[0] ) AmmoIcon[0] = TexMan.CheckForTexture("graphics/HUD/SilverBulletXSBMag.png",TexMan.Type_Any);
|
|
if ( !AmmoIcon[1] ) AmmoIcon[1] = TexMan.CheckForTexture("graphics/HUD/SilverBulletFCBMag.png",TexMan.Type_Any);
|
|
if ( !ZoomBar ) ZoomBar = TexMan.CheckForTexture("graphics/HUD/SilverBulletZoomBar.png",TexMan.Type_Any);
|
|
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
|
|
int zl = clamp(ZoomInter?ZoomInter.GetValue():int(zoomlevel*10),0,160);
|
|
if ( zl >= 10 )
|
|
{
|
|
Screen.DrawTexture(WeaponBox[1],false,bx-35,by-56,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
double zw = zl*31./160.;
|
|
Screen.DrawTexture(ZoomBar,false,bx-33,by-54,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,zw);
|
|
}
|
|
Screen.DrawTexture(WeaponBox[0],false,bx-55,by-44,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
if ( chambered ) Screen.DrawTexture(BulletIcon[fcbchambered],false,bx-53,by-30,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fired?Color(128,0,0,0):Color(0,0,0,0));
|
|
for ( int i=0; i<ClipCount; i++ )
|
|
Screen.DrawTexture(BulletIcon[fcbloaded],false,bx-53,(by-22)+i*4,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawTexture(AmmoIcon[0],false,bx-18,by-19,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
|
Screen.DrawTexture(AmmoIcon[1],false,bx-18,by-41,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
|
int cx = (Ammo1.Amount>9)?32:29;
|
|
int sb = Owner.CountInv("SilverBullets");
|
|
if ( sb > 0 )
|
|
{
|
|
int cbx = (sb>9)?34:30;
|
|
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cbx,by-21,String.Format("⁺%s",SWWMUtility.SuperscriptNum(sb)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
|
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-14,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
|
}
|
|
else Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-18,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
|
cx = (Ammo2.Amount>9)?32:29;
|
|
sb = Owner.CountInv("SilverBullets2");
|
|
if ( sb > 0 )
|
|
{
|
|
int cbx = (sb>9)?34:30;
|
|
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cbx,by-43,String.Format("⁺%s",SWWMUtility.SuperscriptNum(sb)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
|
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-36,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
|
}
|
|
else Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-40,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
|
}
|
|
override void HudTick()
|
|
{
|
|
Super.HudTick();
|
|
if ( !ZoomInter ) ZoomInter = DynamicValueInterpolator.Create(int(zoomlevel*10),.5,1,20);
|
|
ZoomInter.Update(int(zoomlevel*10));
|
|
}
|
|
|
|
override bool ReportHUDAmmo()
|
|
{
|
|
if ( (chambered && !fired) || (clipcount > 0) ) return true;
|
|
if ( (Ammo1.Amount <= 0) && (Ammo2.Amount <= 0) && (Owner.CountInv("SilverBullets") <= 0) && (Owner.CountInv("SilverBullets2") <= 0) ) return false;
|
|
return true;
|
|
}
|
|
override bool CheckAmmo( int firemode, bool autoswitch, bool requireammo, int ammocount )
|
|
{
|
|
if ( sv_infiniteammo || Owner.FindInventory('PowerInfiniteAmmo',true) ) return true;
|
|
if ( (fireMode == PrimaryFire) || (fireMode == AltFire) )
|
|
{
|
|
// allow player to still use the zoom even if there's no ammo left
|
|
// (should work fine, assuming I've correctly interpreted the execution chain of all this stuff)
|
|
if ( autoswitch && (fireMode == AltFire) ) return true;
|
|
return ((chambered && !fired) || (clipcount > 0) || (Ammo1.Amount > 0) || (Ammo2.Amount > 0) || (Owner.CountInv("SilverBullets") > 0) || (Owner.CountInv("SilverBullets2") > 0));
|
|
}
|
|
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
|
|
}
|
|
override void DetachFromOwner()
|
|
{
|
|
// force disable zoom
|
|
zoomed = false;
|
|
if ( Owner.player == players[consoleplayer] )
|
|
Shader.SetEnabled(players[consoleplayer],"SilverScope",false);
|
|
Super.DetachFromOwner();
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( zoomed ) crosshair = 99;
|
|
if ( !Owner || !Owner.player )
|
|
{
|
|
proneme = false;
|
|
lookscale = 1.;
|
|
return;
|
|
}
|
|
if ( (Owner.player.ReadyWeapon == self) && Owner.player.mo.CanCrouch() && (Owner.player.crouchfactor <= .5) )
|
|
{
|
|
if ( !proneme ) Owner.A_StartSound("silverbullet/crouch",CHAN_WEAPONEXTRA,CHANF_OVERLAP);
|
|
proneme = true;
|
|
lookscale = .4;
|
|
return;
|
|
}
|
|
if ( proneme ) Owner.A_StartSound("silverbullet/uncrouch",CHAN_WEAPONEXTRA,CHANF_OVERLAP);
|
|
proneme = false;
|
|
lookscale = 1.;
|
|
}
|
|
override void RenderUnderlay( RenderEvent e )
|
|
{
|
|
if ( !useshaders ) useshaders = CVar.GetCVar('swwm_shaders',players[consoleplayer]);
|
|
if ( zoomed && (Owner.player == players[consoleplayer]) )
|
|
{
|
|
Vector2 ss = (Screen.GetWidth(),Screen.GetHeight());
|
|
ss *= (512./ss.y);
|
|
if ( useshaders.GetBool() ) Shader.SetEnabled(players[consoleplayer],"SilverScope",true);
|
|
else
|
|
{
|
|
Shader.SetEnabled(players[consoleplayer],"SilverScope",false);
|
|
if ( !scope ) scope = TexMan.CheckForTexture("graphics/SBScope.png",TexMan.Type_Any);
|
|
Screen.DrawTexture(scope,false,ss.x*.5,ss.y*.5,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Multiply);
|
|
}
|
|
if ( !reticle ) reticle = TexMan.CheckForTexture("graphics/SBReticle.png",TexMan.Type_Any);
|
|
Screen.DrawTexture(reticle,false,ss.x*.5,ss.y*.5,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Stencil,DTA_FillColor,Color(0,0,0));
|
|
return;
|
|
}
|
|
else Shader.SetEnabled(players[consoleplayer],"SilverScope",false);
|
|
Super.RenderUnderlay(e);
|
|
}
|
|
|
|
action void ProcessTraceHit( SilverBulletTracer t, Vector3 origin, Vector3 dir )
|
|
{
|
|
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
|
{
|
|
t.ShootThroughList[i].Activate(self,0,SPAC_PCross);
|
|
if ( t.ShootThroughList[i].special == GlassBreak ) // fuck glass
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_Impact);
|
|
}
|
|
for ( int i=0; i<t.WaterHitList.Size(); i++ )
|
|
{
|
|
let b = Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
|
|
b.A_CheckTerrain();
|
|
}
|
|
for ( int i=4; i<t.Results.Distance; i+=8 )
|
|
{
|
|
if ( !Random[Boolet](0,1) ) continue;
|
|
Vector3 ofs = level.Vec3Offset(origin,dir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
let b = Spawn("SWWMHalfSmoke",ofs);
|
|
b.Scale *= FRandom[Boolet](.9,1.6);
|
|
b.alpha *= .5;
|
|
b.special1 = Random[Boolet](0,2);
|
|
}
|
|
for ( int i=0; i<t.HitList.Size(); i++ )
|
|
{
|
|
int realdmg = t.HitList[i].HitDamage;
|
|
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',false,DMG_FOILINVUL);
|
|
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),realdmg*20.*FRandom[SilverBullet](.8,1.2));
|
|
if ( t.HitList[i].HitActor && !t.HitList[i].HitActor.bNOBLOOD && !t.HitList[i].HitActor.bDORMANT )
|
|
{
|
|
t.HitList[i].HitActor.TraceBleed(realdmg,self);
|
|
t.HitList[i].HitActor.SpawnBlood(t.HitList[i].HitLocation,atan2(t.HitList[i].x.y,t.HitList[i].x.x)+180,realdmg);
|
|
t.HitList[i].HitActor.A_StartSound("silverbullet/flesh",CHAN_DAMAGE,CHANF_OVERLAP,1.,2.);
|
|
let p = Spawn("SilverImpact",t.HitList[i].HitLocation);
|
|
p.special1 = 1;
|
|
p.target = self;
|
|
}
|
|
else
|
|
{
|
|
let p = Spawn("SilverImpact",t.HitList[i].HitLocation);
|
|
p.angle = atan2(t.HitList[i].x.y,t.HitList[i].x.x)+180;
|
|
p.pitch = asin(t.HitList[i].x.z);
|
|
p.target = self;
|
|
}
|
|
}
|
|
LineTracer faketracer = new("LineTracer");
|
|
for ( int i=0; i<t.WallPenetrateList.Size(); i++ )
|
|
{
|
|
Vector3 hitpos = t.WallPenetrateList[i].hitpos;
|
|
Vector3 hitnormal = t.WallPenetrateList[i].hitnormal;
|
|
let p = Spawn("SilverImpact",hitpos+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = self;
|
|
if ( t.WallPenetrateList[i].hittype == TRACE_HitWall )
|
|
t.WallPenetrateList[i].hitline.Activate(self,t.WallPenetrateList[i].hitside,SPAC_Impact);
|
|
if ( swwm_omnibust )
|
|
{
|
|
faketracer.Results.HitType = t.WallPenetrateList[i].HitType;
|
|
faketracer.Results.HitSector = t.WallPenetrateList[i].HitSector;
|
|
faketracer.Results.HitLine = t.WallPenetrateList[i].HitLine;
|
|
faketracer.Results.ffloor = t.WallPenetrateList[i].HitFFloor;
|
|
faketracer.Results.Side = t.WallPenetrateList[i].HitSide;
|
|
faketracer.Results.Tier = t.WallPenetrateList[i].HitTier;
|
|
BusterWall.Bust(faketracer.Results,t.WallPenetrateList[i].penetration,self,t.WallPenetrateList[i].BustDir,t.WallPenetrateList[i].HitPos.z);
|
|
}
|
|
}
|
|
if ( (t.Results.HitType != TRACE_HitNone) && (t.Results.HitType != TRACE_HasHitSky) && (t.Results.HitType != TRACE_HitActor) )
|
|
{
|
|
Vector3 hitnormal = -t.Results.HitVector;
|
|
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;
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
|
|
if ( !t.Results.Side ) hitnormal *= -1;
|
|
}
|
|
let p = Spawn("SilverImpact",t.Results.HitPos+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = self;
|
|
if ( t.Results.HitType == TRACE_HitWall ) t.Results.HitLine.RemoteActivate(self,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
|
if ( swwm_omnibust ) BusterWall.Bust(t.Results,int(t.penetration),self,t.Results.HitVector,t.Results.HitPos.z);
|
|
}
|
|
for ( int i=0; i<t.Results.Distance; i+=16 )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(origin,dir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
let s = Spawn("SilverAirRip",ofs);
|
|
s.target = self;
|
|
}
|
|
}
|
|
action void ProcessAltTraceHit( FatChodeTracer t, Vector3 origin, Vector3 dir )
|
|
{
|
|
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
|
{
|
|
t.ShootThroughList[i].Activate(self,0,SPAC_PCross);
|
|
if ( t.ShootThroughList[i].special == GlassBreak ) // fuck glass
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_Impact);
|
|
}
|
|
for ( int i=0; i<t.WaterHitList.Size(); i++ )
|
|
{
|
|
let b = Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
|
|
b.A_CheckTerrain();
|
|
}
|
|
for ( int i=4; i<t.Results.Distance; i+=8 )
|
|
{
|
|
if ( !Random[Boolet](0,1) ) continue;
|
|
Vector3 ofs = level.Vec3Offset(origin,dir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
let b = Spawn("SWWMHalfSmoke",ofs);
|
|
b.Scale *= FRandom[Boolet](.9,1.6);
|
|
b.alpha *= .5;
|
|
b.special1 = Random[Boolet](0,2);
|
|
}
|
|
if ( (t.Results.HitType != TRACE_HitNone) && (t.Results.HitType != TRACE_HasHitSky) )
|
|
{
|
|
Vector3 hitnormal = -t.Results.HitVector;
|
|
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;
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
|
|
if ( !t.Results.Side ) hitnormal *= -1;
|
|
}
|
|
if ( t.Results.HitType == TRACE_HitActor )
|
|
{
|
|
int dmg = t.Results.HitActor.DamageMobj(invoker,self,invoker.proneme?1000:500,'shot',DMG_FOILINVUL|DMG_USEANGLE|DMG_THRUSTLESS,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
|
|
SWWMUtility.DoKnockback(t.Results.HitActor,t.Results.HitVector+(0,0,.025),dmg*20.*FRandom[SilverBullet](.8,1.2));
|
|
if ( t.Results.HitActor && !t.Results.HitActor.bNOBLOOD && !t.Results.HitActor.bDORMANT )
|
|
{
|
|
t.Results.HitActor.TraceBleed(dmg,self);
|
|
t.Results.HitActor.SpawnBlood(t.Results.HitPos,atan2(t.Results.HitVector.y,t.Results.HitVector.x)+180,dmg);
|
|
t.Results.HitActor.A_StartSound("silverbullet/flesh",CHAN_DAMAGE,CHANF_OVERLAP,1.,2.);
|
|
}
|
|
}
|
|
else if ( t.Results.HitType == TRACE_HitWall )
|
|
t.Results.HitLine.RemoteActivate(self,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
|
let p = Spawn("FatChodeImpact",t.Results.HitPos+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = self;
|
|
FatChodeImpact(p).realangle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
|
|
FatChodeImpact(p).realpitch = asin(-t.Results.HitVector.z);
|
|
BusterWall.Bust(t.Results,invoker.proneme?2500:2000,self,t.Results.HitVector,t.Results.HitPos.z);
|
|
}
|
|
for ( int i=0; i<t.Results.Distance; i+=16 )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(origin,dir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
let s = Spawn("SilverAirRip2",ofs);
|
|
s.target = self;
|
|
}
|
|
}
|
|
override Vector3 GetTraceOffset()
|
|
{
|
|
if ( zoomed ) return (0.,0.,0.);
|
|
return (10.,1,-1.);
|
|
}
|
|
action void A_SilverFire()
|
|
{
|
|
A_SWWMFlash();
|
|
A_StartSound(invoker.fcbchambered?"silverbullet/altfire":"silverbullet/fire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.3);
|
|
A_AlertMonsters(swwm_uncapalert?0:16000);
|
|
int str = invoker.fcbchambered?7:8;
|
|
A_QuakeEx(str,str,str,10,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:str/4.);
|
|
double basezoom = invoker.zoomed?clamp(invoker.zoomlevel,1.,16.):1.;
|
|
A_ZoomFactor(basezoom*(invoker.fcbchambered?.8:.76),ZOOM_INSTANT);
|
|
A_ZoomFactor(basezoom);
|
|
A_PlayerFire();
|
|
SWWMHandler.DoFlash(self,Color(110,255,192,80),8);
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = Vec2OffsetZ(0,0,player.viewz);
|
|
if ( !invoker.zoomed ) origin = level.Vec3Offset(origin,10*x+1*y-1*z);
|
|
Vector3 x2, y2, z2;
|
|
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
if ( invoker.fcbchambered )
|
|
{
|
|
FatChodeTracer sst = new("FatChodeTracer");
|
|
sst.ignoreme = self;
|
|
sst.shootthroughlist.Clear();
|
|
sst.waterhitlist.Clear();
|
|
sst.Trace(origin,level.PointInSector(origin.xy),x2,20000.,TRACE_HitSky);
|
|
ProcessAltTraceHit(sst,origin,x2);
|
|
}
|
|
else
|
|
{
|
|
SilverBulletTracer sst = new("SilverBulletTracer");
|
|
sst.ignoreme = self;
|
|
sst.penetration = invoker.proneme?2500.:1500.;
|
|
sst.hitlist.Clear();
|
|
sst.shootthroughlist.Clear();
|
|
sst.waterhitlist.Clear();
|
|
sst.wallpenetratelist.Clear();
|
|
sst.Trace(origin,level.PointInSector(origin.xy),x2,20000.,TRACE_HitSky);
|
|
ProcessTraceHit(sst,origin,x2);
|
|
}
|
|
for ( int i=0; i<10; i++ )
|
|
{
|
|
let s = Spawn("SWWMViewSmoke",origin);
|
|
SWWMViewSmoke(s).ofs = (10,1,-1);
|
|
s.target = self;
|
|
s.SetShade(Color(1,1,1)*Random[Silverbullet](96,192));
|
|
s.alpha *= .5;
|
|
}
|
|
for ( int i=0; i<16; i++ )
|
|
{
|
|
let s = Spawn("SWWMSmoke",origin);
|
|
s.scale *= 1.3;
|
|
s.alpha *= .5;
|
|
s.special1 = Random[Silverbullet](0,3);
|
|
s.SetShade(Color(1,1,1)*Random[Silverbullet](96,192));
|
|
s.vel += vel*.5+x*FRandom[Silverbullet](2.,7.)+y*FRandom[Silverbullet](-2.,2.)+z*FRandom[Silverbullet](-2.,2.);
|
|
}
|
|
for ( int i=0; i<34; i++ )
|
|
{
|
|
let s = Spawn("SWWMSmoke",origin);
|
|
s.scale *= 1.8;
|
|
s.alpha *= .8;
|
|
s.special1 = Random[Silverbullet](0,2);
|
|
s.SetShade(Color(1,1,1)*Random[Silverbullet](96,192));
|
|
s.vel += vel*.5+y*FRandom[Silverbullet](2.,8.)*RandomPick[SilverBullet](-1,1);
|
|
}
|
|
for ( int i=0; i<20; i++ )
|
|
{
|
|
let s = Spawn("SWWMSpark",origin);
|
|
s.scale *= .4;
|
|
s.alpha *= .4;
|
|
s.vel += vel*.5+x*FRandom[Silverbullet](4.,8.)+y*FRandom[Silverbullet](-1,1)+z*FRandom[Silverbullet](-1,1);
|
|
}
|
|
double fact = invoker.fcbchambered?270000.:320000.;
|
|
if ( invoker.proneme ) fact /= 8.;
|
|
else A_Overlay(-9999,"Jet");
|
|
SWWMUtility.DoKnockback(self,-x,fact);
|
|
}
|
|
action void A_DropCasing( bool fcb = false )
|
|
{
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+10*y-8*z);
|
|
let c = Spawn(fcb?"SilverBulletCasing2":"SilverBulletCasing",origin);
|
|
c.angle = angle;
|
|
c.pitch = pitch;
|
|
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](4,8)-(0,0,FRandom[Junk](1,3));
|
|
c.vel += vel*.5;
|
|
}
|
|
action void A_DropBullet( bool fcb = false )
|
|
{
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+10*y-8*z);
|
|
Class<MagAmmo> mac = fcb?"SilverBullets2":"SilverBullets";
|
|
MagAmmo ma = MagAmmo(FindInventory(mac));
|
|
if ( !ma )
|
|
{
|
|
ma = MagAmmo(Spawn(mac));
|
|
ma.Amount = 0;
|
|
ma.AttachToOwner(self);
|
|
}
|
|
if ( ma.Amount < ma.MaxAmount )
|
|
{
|
|
ma.Amount++;
|
|
ma.MagFill();
|
|
}
|
|
else
|
|
{
|
|
let c = Spawn(mac,origin);
|
|
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](4,8)-(0,0,FRandom[Junk](1,3));
|
|
c.vel += vel*.5;
|
|
}
|
|
}
|
|
action void A_DropMag()
|
|
{
|
|
if ( invoker.clipcount >= invoker.default.clipcount )
|
|
{
|
|
if ( invoker.fcbloaded )
|
|
{
|
|
if ( (invoker.Ammo2.Amount >= invoker.Ammo2.MaxAmount) && !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
|
Spawn(invoker.AmmoType2,Vec3Angle(5,angle,height/2));
|
|
else invoker.Ammo2.Amount = min(invoker.Ammo2.MaxAmount,invoker.Ammo2.Amount+1);
|
|
}
|
|
else
|
|
{
|
|
if ( (invoker.Ammo1.Amount >= invoker.Ammo1.MaxAmount) && !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
|
Spawn(invoker.AmmoType1,Vec3Angle(5,angle,height/2));
|
|
else invoker.Ammo1.Amount = min(invoker.Ammo1.MaxAmount,invoker.Ammo1.Amount+1);
|
|
}
|
|
invoker.ClipCount = 0;
|
|
return; // no mag dropped
|
|
}
|
|
else
|
|
{
|
|
Class<MagAmmo> mac = invoker.fcbloaded?"SilverBullets2":"SilverBullets";
|
|
MagAmmo ma = MagAmmo(FindInventory(mac));
|
|
if ( !ma )
|
|
{
|
|
ma = MagAmmo(Spawn(mac));
|
|
ma.Amount = 0;
|
|
ma.AttachToOwner(self);
|
|
}
|
|
int maxgiveamt = min(ma.MaxAmount-ma.Amount,invoker.clipcount);
|
|
int dropamt = invoker.clipcount-maxgiveamt;
|
|
if ( dropamt > 0 ) ma.CreateTossable(dropamt);
|
|
ma.Amount = min(ma.MaxAmount,ma.Amount+invoker.clipcount);
|
|
ma.MagFill();
|
|
if ( CheckLocalView() ) for ( int i=0; i<min(ma.Amount,invoker.clipcount-dropamt); i++ ) ma.PrintPickupMessage(true,ma.PickupMessage());
|
|
if ( min(ma.Amount,invoker.clipcount-dropamt) > 0 ) ma.PlayPickupSound(self);
|
|
}
|
|
invoker.ClipCount = 0;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),6*x-15*z);
|
|
let c = Spawn(invoker.fcbloaded?"SilverBulletMag2":"SilverBulletMag",origin);
|
|
c.angle = angle;
|
|
c.pitch = pitch;
|
|
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](-.5,.5)-(0,0,FRandom[Junk](2,3));
|
|
c.vel += vel*.5;
|
|
}
|
|
action void A_JetCompensate()
|
|
{
|
|
invoker.specialf1 -= .06;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
|
vel += x*min(1.,invoker.specialf1)*(600./Mass);
|
|
A_OverlayAlpha(PSP_WEAPON+2,clamp(invoker.specialf1*3.,0.,1.));
|
|
if ( Random[SilverBullet](0,int(invoker.specialf1*2)) )
|
|
self.DamageMobj(invoker,self,1,'jet');
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),-x*10-z*10);
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
let s = Spawn("SWWMSmoke",origin);
|
|
s.scale *= 1.3;
|
|
s.alpha *= .5*invoker.specialf1;
|
|
s.special1 = Random[Silverbullet](0,3);
|
|
s.SetShade(Color(1,1,1)*Random[Silverbullet](224,255));
|
|
s.vel += vel*.5+x*FRandom[Silverbullet](-8.,-5.)+y*FRandom[Silverbullet](3.,6.)*RandomPick[Silverbullet](-1,1)+z*FRandom[Silverbullet](-3.,-2.);
|
|
}
|
|
}
|
|
|
|
action void A_SwitchAmmoType( bool ifempty = false )
|
|
{
|
|
bool oldsel = invoker.fcbselected;
|
|
if ( invoker.fcbselected && ((invoker.Ammo1.Amount > 0) || (CountInv("SilverBullets") > 0)) )
|
|
invoker.fcbselected = (ifempty&&((invoker.Ammo2.Amount>0)||(CountInv("SilverBullets2")>0)))?true:false;
|
|
else if ( !invoker.fcbselected && ((invoker.Ammo2.Amount > 0) || (CountInv("SilverBullets2") > 0)) )
|
|
invoker.fcbselected = (ifempty&&((invoker.Ammo1.Amount>0)||(CountInv("SilverBullets")>0)))?false:true;
|
|
if ( oldsel != invoker.fcbselected ) A_StartSound("misc/invchange",CHAN_WEAPONEXTRA,CHANF_UI|CHANF_LOCAL);
|
|
A_WeaponReady(WRF_NOFIRE);
|
|
}
|
|
action void A_AltHold()
|
|
{
|
|
A_WeaponReady(WRF_NOFIRE);
|
|
// tap fire to unload round
|
|
if ( player.cmd.buttons&BT_ATTACK )
|
|
{
|
|
player.SetPSPrite(PSP_WEAPON,invoker.FindState("Cock"));
|
|
return;
|
|
}
|
|
if ( player.cmd.buttons&BT_ALTATTACK ) return;
|
|
A_SwitchAmmoType();
|
|
if ( invoker.zoomed ) player.SetPSPrite(PSP_WEAPON,invoker.FindState("ZoomReady"));
|
|
else player.SetPSPrite(PSP_WEAPON,invoker.fcbloaded?invoker.FindState("Ready2"):invoker.FindState("Ready"));
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_SILVERBULLET";
|
|
Inventory.PickupMessage "$T_SILVERBULLET";
|
|
Obituary "$O_SILVERBULLET";
|
|
Inventory.Icon "graphics/HUD/Icons/W_SilverBullet.png";
|
|
Weapon.SlotNumber 8;
|
|
Weapon.SelectionOrder 800;
|
|
Weapon.UpSound "silverbullet/select";
|
|
Stamina 400000;
|
|
Weapon.AmmoType1 "SilverBulletAmmo";
|
|
Weapon.AmmoGive1 1;
|
|
Weapon.AmmoType2 "SilverBulletAmmo2";
|
|
Weapon.AmmoGive2 0;
|
|
//SWWMWeapon.SwapWeapon "EMPCarbine";
|
|
SWWMWeapon.DropAmmoType "SilverBulletAmmo";
|
|
SilverBullet.ClipCount 5;
|
|
+SWWMWEAPON.NOFIRSTGIVE;
|
|
+WEAPON.ALT_AMMO_OPTIONAL;
|
|
+WEAPON.EXPLOSIVE;
|
|
Radius 36;
|
|
Height 36;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
Select:
|
|
XZW2 G 0 A_JumpIf(invoker.fcbloaded,"Select2");
|
|
XZW2 G 2 A_FullRaise();
|
|
XZW2 HIJKLMN 2;
|
|
Goto Ready;
|
|
Select2:
|
|
XZW8 G 2 A_FullRaise();
|
|
XZW8 HIJKLMN 2;
|
|
Goto Ready2;
|
|
Ready:
|
|
XZW2 A 1
|
|
{
|
|
int flg = WRF_ALLOWRELOAD|WRF_ALLOWZOOM|WRF_ALLOWUSER1;
|
|
A_WeaponReady(flg);
|
|
if ( player.cmd.buttons&BT_ATTACK )
|
|
invoker.CheckAmmo(EitherFire,true);
|
|
}
|
|
Wait;
|
|
Ready2:
|
|
XZW8 A 1
|
|
{
|
|
int flg = WRF_ALLOWRELOAD|WRF_ALLOWZOOM|WRF_ALLOWUSER1;
|
|
A_WeaponReady(flg);
|
|
if ( player.cmd.buttons&BT_ATTACK )
|
|
invoker.CheckAmmo(EitherFire,true);
|
|
}
|
|
Wait;
|
|
ZoomReady:
|
|
TNT1 A 1
|
|
{
|
|
int flg = WRF_ALLOWRELOAD|WRF_ALLOWUSER1;
|
|
if ( invoker.rezoom > 0 ) invoker.rezoom--;
|
|
else flg |= WRF_ALLOWZOOM;
|
|
A_WeaponReady(flg);
|
|
if ( player.cmd.buttons&BT_ATTACK )
|
|
invoker.CheckAmmo(EitherFire,true);
|
|
}
|
|
Wait;
|
|
AltFire:
|
|
#### # 1 A_AltHold();
|
|
Wait;
|
|
Fire:
|
|
XZW2 A 1
|
|
{
|
|
if ( (player.cmd.buttons&BT_ALTATTACK) && invoker.chambered )
|
|
return ResolveState("Cock");
|
|
if ( !invoker.chambered || invoker.fired )
|
|
{
|
|
if ( !invoker.fired && (invoker.clipcount <= 0) && (sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) || (invoker.Ammo1.Amount > 0) || (invoker.Ammo2.Amount > 0) || (CountInv("SilverBullets") > 0) || (CountInv("SilverBullets2") > 0)) )
|
|
{
|
|
A_SwitchAmmoType(true);
|
|
return ResolveState("Reload");
|
|
}
|
|
return ResolveState("Cock");
|
|
}
|
|
A_SilverFire();
|
|
invoker.fired = true;
|
|
if ( invoker.zoomed ) return ResolveState("ZoomFire");
|
|
return A_JumpIf(invoker.fcbloaded,"Fire2");
|
|
}
|
|
XZW2 OPQR 2;
|
|
XZW2 STUVW 3;
|
|
XZW2 A 1 A_JumpIf(invoker.specialf1<=0.,"Ready");
|
|
Wait;
|
|
Fire2:
|
|
XZW8 A 1;
|
|
XZW8 OPQR 2;
|
|
XZW8 STUVW 3;
|
|
XZW8 A 1 A_JumpIf(invoker.specialf1<=0.,"Ready2");
|
|
Wait;
|
|
Jet:
|
|
TNT1 A 3
|
|
{
|
|
invoker.specialf1 = 1.5;
|
|
}
|
|
TNT1 A 0
|
|
{
|
|
A_StartSound("silverbullet/jet",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_Overlay(PSP_WEAPON+2,"JetSmoke");
|
|
A_OverlayFlags(PSP_WEAPON+2,PSPF_RENDERSTYLE|PSPF_ALPHA|PSPF_FORCESTYLE|PSPF_FORCEALPHA,true);
|
|
A_OverlayRenderStyle(PSP_WEAPON+2,STYLE_Add);
|
|
}
|
|
TNT1 A 1
|
|
{
|
|
A_JetCompensate();
|
|
return A_JumpIf(invoker.specialf1<=0.,1);
|
|
}
|
|
Wait;
|
|
TNT1 A 1;
|
|
Stop;
|
|
JetSmoke:
|
|
XZW7 PQR 2;
|
|
XZW7 STUVW 3;
|
|
XZW7 X 1 A_JumpIf(invoker.specialf1<=0.,1);
|
|
Wait;
|
|
TNT1 A 1;
|
|
Stop;
|
|
Cock:
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = invoker.fcbloaded?ResolveState("DoCock2"):ResolveState("DoCock");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return invoker.fcbloaded?ResolveState("DoCock2"):ResolveState("DoCock");
|
|
}
|
|
DoCock:
|
|
XZW2 A 2 A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW2 XYZ 2;
|
|
XZW3 AB 2;
|
|
XZW3 C 2
|
|
{
|
|
A_StartSound("silverbullet/boltopen",CHAN_WEAPON,CHANF_OVERLAP);
|
|
if ( invoker.chambered )
|
|
{
|
|
if ( invoker.fired )
|
|
{
|
|
if ( invoker.fcbchambered ) A_Overlay(PSP_WEAPON+1,"Casing2");
|
|
else A_Overlay(PSP_WEAPON+1,"Casing");
|
|
}
|
|
else
|
|
{
|
|
if ( invoker.fcbchambered ) A_Overlay(PSP_WEAPON+1,"Bullet2");
|
|
else A_Overlay(PSP_WEAPON+1,"Bullet");
|
|
}
|
|
}
|
|
invoker.fired = false;
|
|
invoker.chambered = (invoker.clipcount>0);
|
|
if ( invoker.clipcount > 0 ) invoker.fcbchambered = invoker.fcbloaded;
|
|
invoker.clipcount = max(0,invoker.clipcount-1);
|
|
}
|
|
XZW3 DEFG 2;
|
|
XZW3 H 2 A_StartSound("silverbullet/boltclose",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW3 I 2 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW3 JKLMNOPQR 2;
|
|
Goto Ready;
|
|
DoCock2:
|
|
XZW8 A 2 A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW8 XYZ 2;
|
|
XZW9 AB 2;
|
|
XZW9 C 2
|
|
{
|
|
A_StartSound("silverbullet/boltopen",CHAN_WEAPON,CHANF_OVERLAP);
|
|
if ( invoker.chambered )
|
|
{
|
|
if ( invoker.fired )
|
|
{
|
|
if ( invoker.fcbchambered ) A_Overlay(PSP_WEAPON+1,"Casing2");
|
|
else A_Overlay(PSP_WEAPON+1,"Casing");
|
|
}
|
|
else
|
|
{
|
|
if ( invoker.fcbchambered ) A_Overlay(PSP_WEAPON+1,"Bullet2");
|
|
else A_Overlay(PSP_WEAPON+1,"Bullet");
|
|
}
|
|
}
|
|
invoker.fired = false;
|
|
invoker.chambered = (invoker.clipcount>0);
|
|
if ( invoker.clipcount > 0 ) invoker.fcbchambered = invoker.fcbloaded;
|
|
invoker.clipcount = max(0,invoker.clipcount-1);
|
|
}
|
|
XZW9 DEFG 2;
|
|
XZW9 H 2 A_StartSound("silverbullet/boltclose",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW9 I 2 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW9 JKLMNOPQR 2;
|
|
Goto Ready2;
|
|
Casing:
|
|
XZW7 DE 2;
|
|
XZW7 FGHIJKLMNO 1;
|
|
TNT1 A 0 A_DropCasing();
|
|
Stop;
|
|
Casing2:
|
|
XZWD DE 2;
|
|
XZWD FGHIJKLMNO 1;
|
|
TNT1 A 0 A_DropCasing(true);
|
|
Stop;
|
|
Bullet:
|
|
XZWD PQ 2;
|
|
XZWD RSTUVWXYZ 1;
|
|
XZWE A 1;
|
|
TNT1 A 0 A_DropBullet();
|
|
Stop;
|
|
Bullet2:
|
|
XZWE BC 2;
|
|
XZWE DEFGHIJKLM 1;
|
|
TNT1 A 0 A_DropBullet(true);
|
|
Stop;
|
|
ZoomFire:
|
|
TNT1 A 24;
|
|
TNT1 A 1 A_JumpIf(invoker.specialf1<=0.,"ZoomReady");
|
|
Wait;
|
|
Zoom:
|
|
XZW2 A 0 A_JumpIf(invoker.zoomed,"UnZoom");
|
|
XZW2 A 0 A_JumpIf(invoker.fcbloaded,"Zoom2");
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("silverbullet/zoomstart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
invoker.zoomlevel = 0;
|
|
}
|
|
XZW3 STUVWX 1;
|
|
TNT1 A 1
|
|
{
|
|
invoker.zoomed = true;
|
|
invoker.zoomlevel = clamp(invoker.zoomlevel*1.05+.05,1.,16.);
|
|
A_ZoomFactor(invoker.zoomlevel);
|
|
if ( !(level.maptime%2) && (invoker.zoomlevel < 16.) ) A_StartSound("silverbullet/zooming",CHAN_WEAPON,CHANF_OVERLAP,.2);
|
|
if ( !(player.cmd.buttons&BT_ZOOM) )
|
|
{
|
|
invoker.rezoom = 3;
|
|
return ResolveState("ZoomReady");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Wait;
|
|
Zoom2:
|
|
XZW8 A 0 A_JumpIf(invoker.zoomed,"UnZoom2");
|
|
XZW8 A 2
|
|
{
|
|
A_StartSound("silverbullet/zoomstart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
invoker.zoomlevel = 0;
|
|
}
|
|
XZW9 STUVWX 1;
|
|
TNT1 A 1
|
|
{
|
|
invoker.zoomed = true;
|
|
invoker.zoomlevel = clamp(invoker.zoomlevel*1.05+.05,1.,16.);
|
|
A_ZoomFactor(invoker.zoomlevel);
|
|
if ( !(level.maptime%2) && (invoker.zoomlevel < 16.) ) A_StartSound("silverbullet/zooming",CHAN_WEAPON,CHANF_OVERLAP,.2);
|
|
if ( !(player.cmd.buttons&BT_ZOOM) )
|
|
{
|
|
invoker.rezoom = 3;
|
|
return ResolveState("ZoomReady");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Wait;
|
|
UnZoom:
|
|
XZW3 X 0 A_JumpIf(invoker.fcbloaded,"UnZoom2");
|
|
XZW3 X 1
|
|
{
|
|
A_StartSound("silverbullet/zoomend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
invoker.zoomed = false;
|
|
invoker.zoomlevel = 0;
|
|
A_ZoomFactor(1.,ZOOM_INSTANT);
|
|
}
|
|
XZW3 YZ 1;
|
|
XZW4 ABC 1;
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.dezoomstate )
|
|
{
|
|
State tmp = invoker.dezoomstate;
|
|
invoker.dezoomstate = null;
|
|
return tmp;
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Goto Ready;
|
|
UnZoom2:
|
|
XZW9 X 1
|
|
{
|
|
A_StartSound("silverbullet/zoomend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
invoker.zoomed = false;
|
|
invoker.zoomlevel = 0;
|
|
A_ZoomFactor(1.,ZOOM_INSTANT);
|
|
}
|
|
XZW9 YZ 1;
|
|
XZWA ABC 1;
|
|
XZW8 A 0
|
|
{
|
|
if ( invoker.dezoomstate )
|
|
{
|
|
State tmp = invoker.dezoomstate;
|
|
invoker.dezoomstate = null;
|
|
return tmp;
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Goto Ready2;
|
|
Reload:
|
|
XZW2 A 0
|
|
{
|
|
if ( ((invoker.clipcount >= invoker.default.clipcount) && (invoker.fcbselected == invoker.fcbloaded)) || (!sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) && (invoker.Ammo1.Amount <= 0) && (invoker.Ammo2.Amount <= 0) && (CountInv("SilverBullets") <= 0) && (CountInv("SilverBullets2") <= 0)) )
|
|
return ResolveState("Idle");
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = invoker.fcbloaded?ResolveState("Unload2"):ResolveState("Unload");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return A_JumpIf(invoker.fcbloaded,"Unload2");
|
|
}
|
|
Unload:
|
|
XZW2 A 2
|
|
{
|
|
A_PlayerReload();
|
|
A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
return A_JumpIf(invoker.clipcount<=0,"UnloadEmpty");
|
|
}
|
|
XZW4 DEFGHI 2;
|
|
XZW4 J 2 A_StartSound("silverbullet/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW4 KLMN 2;
|
|
Goto Load;
|
|
UnloadEmpty:
|
|
XZW2 A 2;
|
|
XZW4 OPQRST 2;
|
|
XZW4 U 2 A_StartSound("silverbullet/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW4 VWXY 2;
|
|
Goto Load;
|
|
Unload2:
|
|
XZW8 A 2
|
|
{
|
|
A_PlayerReload();
|
|
A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
return A_JumpIf(invoker.clipcount<=0,"UnloadEmpty2");
|
|
}
|
|
XZWA DEFGHI 2;
|
|
XZWA J 2 A_StartSound("silverbullet/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWA KLMN 2;
|
|
Goto Load;
|
|
UnloadEmpty2:
|
|
XZW8 A 2;
|
|
XZWA OPQRST 2;
|
|
XZWA U 2 A_StartSound("silverbullet/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWA VWXY 2;
|
|
Goto Load;
|
|
Load:
|
|
XZW4 Z 2
|
|
{
|
|
A_DropMag();
|
|
return A_JumpIf(invoker.fcbselected,"Load2");
|
|
}
|
|
XZW5 ABC 2;
|
|
XZW5 D 2
|
|
{
|
|
invoker.fcbloaded = false;
|
|
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
else if ( invoker.Ammo1.Amount <= 0 )
|
|
{
|
|
MagAmmo sb = MagAmmo(FindInventory("SilverBullets"));
|
|
int takeamt = min(sb.Amount,sb.ClipSize);
|
|
invoker.clipcount = takeamt;
|
|
sb.Amount -= takeamt;
|
|
}
|
|
else
|
|
{
|
|
invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1);
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
}
|
|
A_SwitchAmmoType(true);
|
|
A_StartSound("silverbullet/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZW5 E 2 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW5 FGHIJKLMN 2;
|
|
Goto Ready;
|
|
Load2:
|
|
XZWA Z 2;
|
|
XZWB ABC 2;
|
|
XZWB D 2
|
|
{
|
|
invoker.fcbloaded = true;
|
|
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
else if ( invoker.Ammo2.Amount <= 0 )
|
|
{
|
|
MagAmmo sb = MagAmmo(FindInventory("SilverBullets2"));
|
|
int takeamt = min(sb.Amount,sb.ClipSize);
|
|
invoker.clipcount = takeamt;
|
|
sb.Amount -= takeamt;
|
|
}
|
|
else
|
|
{
|
|
invoker.Ammo2.Amount = max(0,invoker.Ammo2.Amount-1);
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
}
|
|
A_SwitchAmmoType(true);
|
|
A_StartSound("silverbullet/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZWB E 2 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWB FGHIJKLMN 2;
|
|
Goto Ready2;
|
|
Idle:
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = invoker.fcbloaded?ResolveState("DoIdle2"):ResolveState("DoIdle");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return invoker.fcbloaded?ResolveState("DoIdle2"):ResolveState("DoIdle");
|
|
}
|
|
DoIdle:
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("silverbullet/idle",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerCheckGun();
|
|
}
|
|
XZW5 OPQR 3;
|
|
XZW5 STUV 2;
|
|
XZW5 WXYZ 3;
|
|
XZW6 ABCD 4;
|
|
XZW6 EFGH 3;
|
|
Goto Ready;
|
|
DoIdle2:
|
|
XZW8 A 2
|
|
{
|
|
A_StartSound("silverbullet/idle",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerCheckGun();
|
|
}
|
|
XZWB OPQR 3;
|
|
XZWB STUV 2;
|
|
XZWB WXYZ 3;
|
|
XZWC ABCD 4;
|
|
XZWC EFGH 3;
|
|
Goto Ready2;
|
|
User1:
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = invoker.fcbloaded?ResolveState("DoUser12"):ResolveState("DoUser1");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return invoker.fcbloaded?ResolveState("DoUser12"):ResolveState("DoUser1");
|
|
}
|
|
DoUser1:
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerMelee();
|
|
}
|
|
XZW6 IJK 3;
|
|
XZW6 L 1 A_Parry(9);
|
|
XZW6 MN 1;
|
|
XZW6 O 1 A_Melee(90,"demolitionist/whitl",1.6);
|
|
XZW6 PQ 1;
|
|
XZW6 RST 2;
|
|
XZW6 U 3 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW6 VWXYZ 3;
|
|
XZW7 ABC 2;
|
|
Goto Ready;
|
|
DoUser12:
|
|
XZW8 A 2
|
|
{
|
|
A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerMelee();
|
|
}
|
|
XZWC IJK 3;
|
|
XZWC L 1 A_Parry(9);
|
|
XZWC MN 1;
|
|
XZWC O 1 A_Melee(90,"demolitionist/whitl",1.6);
|
|
XZWC PQ 1;
|
|
XZWC RST 2;
|
|
XZWC U 3 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZWC VWXYZ 3;
|
|
XZWD ABC 2;
|
|
Goto Ready2;
|
|
Deselect:
|
|
XZW2 A 0
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = invoker.fcbloaded?ResolveState("DoDeselect2"):ResolveState("DoDeselect");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return invoker.fcbloaded?ResolveState("DoDeselect2"):ResolveState("DoDeselect");
|
|
}
|
|
DoDeselect:
|
|
XZW2 A 2 A_StartSound("silverbullet/deselect",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW2 BCDEF 2;
|
|
XZW2 G -1 A_FullLower();
|
|
Stop;
|
|
DoDeselect2:
|
|
XZW8 A 2 A_StartSound("silverbullet/deselect",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW8 BCDEF 2;
|
|
XZW8 G -1 A_FullLower();
|
|
Stop;
|
|
Flash:
|
|
XZWZ A 2 Bright
|
|
{
|
|
let l = Spawn("SWWMWeaponLight",pos);
|
|
l.args[3] = 200;
|
|
l.target = self;
|
|
}
|
|
Stop;
|
|
}
|
|
}
|