1082 lines
31 KiB
Text
1082 lines
31 KiB
Text
// Blackmann-Forx Silver Bullet JET (successor to Silver Bullet from Zanaveth Ultra Suite)
|
|
// Slot 8, replaces Plasma Rifle, Hellstaff, Quietus (hilt)
|
|
|
|
Class WallPenetrate
|
|
{
|
|
Vector3 hitpos, hitdir, hitnormal, bustdir;
|
|
int hitside, hittier, hittype, penetration;
|
|
Line hitline;
|
|
Sector hitsector;
|
|
F3DFloor hitffloor;
|
|
bool pastwall;
|
|
}
|
|
|
|
Class AuxiliarySilverBulletTracer : LineTracer
|
|
{
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
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 : SpreadgunTracer
|
|
{
|
|
double penetration; // please don't laugh
|
|
bool pastwall, fullstop;
|
|
Array<WallPenetrate> WallPenetrateList;
|
|
Vector3 exitpoint;
|
|
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
// liquid splashes
|
|
if ( Results.CrossedWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.hitpos = Results.CrossedWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
else if ( Results.Crossed3DWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.hitpos = Results.Crossed3DWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
if ( Results.HitType == TRACE_HitActor )
|
|
{
|
|
if ( Results.HitActor.bSHOOTABLE )
|
|
{
|
|
let ent = new("HitListEntry");
|
|
ent.hitactor = Results.HitActor;
|
|
ent.hitlocation = Results.HitPos;
|
|
ent.x = Results.HitVector;
|
|
ent.pastwall = pastwall;
|
|
ent.hitdamage = int(penetration);
|
|
if ( (Results.HitActor.Health >= int(penetration)) || Results.HitActor.bNODAMAGE )
|
|
penetration = 0;
|
|
else
|
|
{
|
|
int killdamage = min(Results.HitActor.health,int(penetration));
|
|
penetration = max(0,penetration-killdamage*.4);
|
|
}
|
|
hitlist.Push(ent);
|
|
if ( penetration <= 0 )
|
|
{
|
|
fullstop = true;
|
|
return TRACE_Stop;
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
else if ( Results.HitType != TRACE_HitNone )
|
|
{
|
|
if ( Results.HitType == TRACE_HitWall )
|
|
{
|
|
ShootThroughList.Push(Results.HitLine);
|
|
if ( (Results.Tier == TIER_Middle) && Results.HitLine.sidedef[1] && !(Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
|
return TRACE_Skip;
|
|
}
|
|
for ( int i=1; i<int(penetration/8); i++ )
|
|
{
|
|
Vector3 ofs = Results.HitPos+Results.HitVector*i;
|
|
if ( level.IsPointInLevel(ofs) )
|
|
{
|
|
// double-check if we're piercing through a 3D floor (yes this is a thing that happens, oh boy)
|
|
Sector s = level.PointInSector(ofs.xy);
|
|
bool stop3d = false;
|
|
for ( int j=0; j<s.Get3DFloorCount(); j++ )
|
|
{
|
|
let ff = s.Get3DFloor(j);
|
|
if ( !(ff.flags&(F3DFloor.FF_EXISTS|F3DFloor.FF_SOLID)) ) continue;
|
|
double minz = ff.bottom.ZAtPoint(ofs.xy);
|
|
double maxz = ff.top.ZAtPoint(ofs.xy);
|
|
if ( (ofs.z < minz) || (ofs.z > maxz) ) continue;
|
|
stop3d = true;
|
|
break;
|
|
}
|
|
if ( stop3d ) continue;
|
|
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;
|
|
wp.pastwall = pastwall;
|
|
WallPenetrateList.Push(wp);
|
|
pastwall = true;
|
|
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.,0,ignoreallactors:true);
|
|
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;
|
|
else wp2.hitnormal = wp2.hitdir;
|
|
wp2.pastwall = pastwall;
|
|
WallPenetrateList.Push(wp2);
|
|
fullstop = false;
|
|
exitpoint = ofs;
|
|
return TRACE_Stop;
|
|
}
|
|
}
|
|
fullstop = true;
|
|
return TRACE_Stop;
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
}
|
|
|
|
Class SilverBullet : SWWMWeapon
|
|
{
|
|
bool chambered, fired;
|
|
int clipcount;
|
|
double casex, casey;
|
|
int nkills;
|
|
|
|
transient ui SmoothDynamicValueInterpolator ZoomInter;
|
|
|
|
bool zoomed;
|
|
double zoomlevel;
|
|
ui TextureID reticle, scope;
|
|
int rezoom;
|
|
bool proneme;
|
|
|
|
int wastecycle; // for easter egg
|
|
|
|
State dezoomstate;
|
|
|
|
Property ClipCount : clipcount;
|
|
|
|
override void HudTick()
|
|
{
|
|
Super.HudTick();
|
|
if ( !ZoomInter ) ZoomInter = SmoothDynamicValueInterpolator.Create(zoomlevel*10,.5);
|
|
ZoomInter.Update(zoomlevel*10);
|
|
}
|
|
|
|
override bool ReportHUDAmmo()
|
|
{
|
|
if ( (chambered && !fired) || (clipcount > 0) ) return true;
|
|
if ( (Ammo1.Amount <= 0) && (Owner.CountInv("SilverBullets") <= 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 == EitherFire) )
|
|
{
|
|
if ( (chambered && !fired) || (clipcount > 0) || (Ammo1.Amount > 0) || (Owner.CountInv("SilverBullets") > 0) )
|
|
return true;
|
|
if ( autoswitch ) PlayerPawn(Owner).PickNewWeapon(null);
|
|
return false;
|
|
}
|
|
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
|
|
}
|
|
override void DetachFromOwner()
|
|
{
|
|
// force disable zoom
|
|
zoomed = false;
|
|
if ( Owner.player == players[consoleplayer] )
|
|
PPShader.SetEnabled("SilverScope",false);
|
|
Super.DetachFromOwner();
|
|
}
|
|
override double GetSpeedFactor()
|
|
{
|
|
if ( proneme ) return 0.;
|
|
return 1.;
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner || !Owner.player )
|
|
{
|
|
proneme = false;
|
|
lookscale = 1.;
|
|
return;
|
|
}
|
|
if ( (Owner.player.ReadyWeapon == self) && Owner.player.onground )
|
|
{
|
|
if ( (Owner.player.cmd.buttons&BT_CROUCH) || (Owner.player.crouchdir == -1) )
|
|
{
|
|
if ( !proneme ) Owner.A_StartSound("silverbullet/crouch",CHAN_WEAPONEXTRA,CHANF_OVERLAP);
|
|
proneme = true;
|
|
}
|
|
else
|
|
{
|
|
if ( proneme ) Owner.A_StartSound("silverbullet/uncrouch",CHAN_WEAPONEXTRA,CHANF_OVERLAP);
|
|
proneme = false;
|
|
}
|
|
}
|
|
else proneme = false;
|
|
lookscale = proneme?.4:1.;
|
|
}
|
|
override void RenderUnderlay( RenderEvent e )
|
|
{
|
|
if ( zoomed && (Owner.player == players[consoleplayer]) )
|
|
{
|
|
Vector2 ss = (Screen.GetWidth(),Screen.GetHeight());
|
|
ss *= (512./ss.y);
|
|
if ( swwm_shaders ) PPShader.SetEnabled("SilverScope",true);
|
|
else
|
|
{
|
|
PPShader.SetEnabled("SilverScope",false);
|
|
if ( !scope ) scope = TexMan.CheckForTexture("graphics/SBScope.png");
|
|
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");
|
|
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 PPShader.SetEnabled("SilverScope",false);
|
|
Super.RenderUnderlay(e);
|
|
}
|
|
override bool ShouldDrawCrosshair()
|
|
{
|
|
return !zoomed;
|
|
}
|
|
|
|
action void ProcessTraceHit( SilverBulletTracer t, Vector3 origin, Vector3 dir )
|
|
{
|
|
foreach ( l:t.ShootThroughList )
|
|
{
|
|
l.Activate(self,0,SPAC_Impact);
|
|
l.Activate(self,0,SPAC_PCross);
|
|
}
|
|
foreach ( w:t.WaterHitList )
|
|
{
|
|
let b = Spawn("InvisibleSplasher",w.hitpos);
|
|
b.target = self;
|
|
b.A_CheckTerrain();
|
|
}
|
|
foreach( hit:t.HitList )
|
|
{
|
|
if ( !hit.HitActor ) continue;
|
|
SWWMUtility.DoKnockback(hit.HitActor,hit.x+(0,0,0.025),hit.HitDamage*20.*FRandom[SilverBullet](.8,1.2));
|
|
let p = SWWMPuff.Setup(hit.HitLocation,hit.x,invoker,self,hit.HitActor);
|
|
int dmg = hit.HitActor.DamageMobj(p,self,hit.HitDamage,'Sniped',DMG_FOILINVUL|DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
|
|
if ( hit.HitActor && (hit.HitActor.Health <= 0) && (hit.HitActor.bIsMonster || hit.HitActor.player) && hit.HitActor.IsHostile(self) )
|
|
{
|
|
invoker.nkills++;
|
|
SWWMUtility.AchievementProgress("conga",invoker.nkills,player);
|
|
if ( hit.pastwall ) SWWMUtility.AchievementProgressInc("thruwall",1,player);
|
|
}
|
|
if ( (dmg > 0) && hit.HitActor && !hit.HitActor.bNOBLOOD && !hit.HitActor.bDORMANT )
|
|
{
|
|
hit.HitActor.TraceBleed(dmg,self);
|
|
hit.HitActor.SpawnBlood(hit.HitLocation,atan2(hit.x.y,hit.x.x)+180,dmg);
|
|
hit.HitActor.A_StartSound("silverbullet/flesh",CHAN_DAMAGE,CHANF_OVERLAP,1.,2.);
|
|
let p = Spawn("SilverImpact",hit.HitLocation);
|
|
p.special1 = 1;
|
|
p.target = self;
|
|
p.master = invoker;
|
|
p.bAMBUSH = hit.pastwall;
|
|
}
|
|
else
|
|
{
|
|
let p = Spawn("SilverImpact",hit.HitLocation);
|
|
p.angle = atan2(hit.x.y,hit.x.x)+180;
|
|
p.pitch = asin(hit.x.z);
|
|
p.target = self;
|
|
p.master = invoker;
|
|
p.bAMBUSH = hit.pastwall;
|
|
}
|
|
}
|
|
LineTracer faketracer = new("LineTracer");
|
|
foreach ( wp:t.WallPenetrateList )
|
|
{
|
|
Vector3 hitpos = wp.hitpos;
|
|
Vector3 hitnormal = wp.hitnormal;
|
|
let p = Spawn("SilverImpact",hitpos+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = self;
|
|
p.master = invoker;
|
|
p.bAMBUSH = wp.pastwall;
|
|
if ( wp.hittype == TRACE_HitWall )
|
|
wp.hitline.Activate(self,wp.hitside,SPAC_Impact);
|
|
if ( swwm_omnibust )
|
|
{
|
|
faketracer.Results.HitType = wp.HitType;
|
|
faketracer.Results.HitSector = wp.HitSector;
|
|
faketracer.Results.HitLine = wp.HitLine;
|
|
faketracer.Results.ffloor = wp.HitFFloor;
|
|
faketracer.Results.Side = wp.HitSide;
|
|
faketracer.Results.Tier = wp.HitTier;
|
|
BusterWall.Bust(faketracer.Results,wp.penetration,self,wp.BustDir,wp.HitPos.z);
|
|
}
|
|
}
|
|
if ( (t.Results.HitType != TRACE_HitNone) && (t.Results.HitType != TRACE_HitActor) )
|
|
{
|
|
Vector3 hitnormal = SWWMUtility.GetLineTracerHitNormal(t.Results);
|
|
let p = Spawn("SilverImpact",t.Results.HitPos+hitnormal*4);
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
p.target = self;
|
|
p.master = invoker;
|
|
if ( t.WallPenetrateList.Size() > 0 ) p.bAMBUSH = true;
|
|
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);
|
|
}
|
|
if ( t.WallPenetrateList.Size() > 0 )
|
|
{
|
|
Vector3 start = origin;
|
|
Vector3 end = t.WallPenetrateList[0].hitpos;
|
|
Vector3 tdir = level.Vec3Diff(start,end);
|
|
double dist = tdir.length();
|
|
tdir /= dist;
|
|
SilverAirRip s;
|
|
for ( int i=0; i<dist; i+=16 )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(start,tdir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
if ( s )
|
|
{
|
|
s.SetOrigin(ofs,false);
|
|
s.Explode();
|
|
continue;
|
|
}
|
|
s = SilverAirRip(Spawn("SilverAirRip",ofs));
|
|
s.target = self;
|
|
s.master = invoker;
|
|
s.Explode();
|
|
}
|
|
for ( int i=4; i<dist; i+=8 )
|
|
{
|
|
if ( !Random[Boolet](0,1) ) continue;
|
|
Vector3 ofs = level.Vec3Offset(start,tdir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
let b = SWWMAnimSprite.SpawnAt("SWWMHalfSmoke",ofs);
|
|
b.Scale *= FRandom[Boolet](.9,1.6);
|
|
b.alpha *= .5;
|
|
b.framestep = Random[Boolet](1,3);
|
|
}
|
|
for ( int i=1; i<t.WallPenetrateList.Size(); i+=2 )
|
|
{
|
|
start = t.WallPenetrateList[i].hitpos;
|
|
if ( i >= t.WallPenetrateList.Size()-1 ) end = t.Results.HitPos;
|
|
else end = t.WallPenetrateList[i+1].hitpos;
|
|
tdir = level.Vec3Diff(start,end);
|
|
dist = tdir.length();
|
|
tdir /= dist;
|
|
for ( int j=0; j<dist; j+=16 )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(start,tdir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
if ( s )
|
|
{
|
|
s.SetOrigin(ofs,false);
|
|
s.Explode(true);
|
|
continue;
|
|
}
|
|
s = SilverAirRip(Spawn("SilverAirRip",ofs));
|
|
s.target = self;
|
|
s.master = invoker;
|
|
s.Explode(true);
|
|
}
|
|
for ( int i=4; i<dist; i+=8 )
|
|
{
|
|
if ( !Random[Boolet](0,1) ) continue;
|
|
Vector3 ofs = level.Vec3Offset(start,tdir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
let b = SWWMAnimSprite.SpawnAt("SWWMHalfSmoke",ofs);
|
|
b.Scale *= FRandom[Boolet](.9,1.6);
|
|
b.alpha *= .5;
|
|
b.framestep = Random[Boolet](1,3);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SilverAirRip s;
|
|
for ( int i=0; i<t.Results.Distance; i+=16 )
|
|
{
|
|
Vector3 ofs = level.Vec3Offset(origin,dir*i);
|
|
if ( !level.IsPointInLevel(ofs) ) continue;
|
|
if ( s )
|
|
{
|
|
s.SetOrigin(ofs,false);
|
|
s.Explode();
|
|
continue;
|
|
}
|
|
s = SilverAirRip(Spawn("SilverAirRip",ofs));
|
|
s.target = self;
|
|
s.master = invoker;
|
|
s.Explode();
|
|
}
|
|
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 = SWWMAnimSprite.SpawnAt("SWWMHalfSmoke",ofs);
|
|
b.Scale *= FRandom[Boolet](.9,1.6);
|
|
b.alpha *= .5;
|
|
b.framestep = Random[Boolet](1,3);
|
|
}
|
|
}
|
|
}
|
|
override Vector3 GetTraceOffset( int index )
|
|
{
|
|
if ( zoomed ) return (0.,0.,0.);
|
|
return (10.,1,-1.);
|
|
}
|
|
action void A_SilverFire()
|
|
{
|
|
A_SWWMFlash();
|
|
A_StartSound("silverbullet/fire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.3);
|
|
A_AlertMonsters(swwm_uncapalert?0:16000);
|
|
A_QuakeEx(8.5,8.5,8.5,15,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:2.2);
|
|
double basezoom = invoker.zoomed?clamp(invoker.zoomlevel,1.,16.):1.;
|
|
A_BumpView(invoker.proneme?-2:-8);
|
|
A_BumpFOV(.64);
|
|
A_PlayerFire();
|
|
SWWMHandler.DoFlash(self,Color(110,255,192,80),8);
|
|
let [x, y, z] = SWWMUtility.GetPlayerAxes(self);
|
|
Vector3 origin;
|
|
if ( !invoker.zoomed ) origin = SWWMUtility.GetFireOffset(self,10,1,-1);
|
|
else origin = SWWMUtility.GetPlayerEye(self);
|
|
let [x2, y2, z2] = SWWMUtility.GetPlayerAxesAutoAimed(self);
|
|
SilverBulletTracer sst = new("SilverBulletTracer");
|
|
sst.penetration = invoker.proneme?1200.:1000.;
|
|
sst.hitlist.Clear();
|
|
sst.shootthroughlist.Clear();
|
|
sst.waterhitlist.Clear();
|
|
sst.wallpenetratelist.Clear();
|
|
sst.pastwall = false;
|
|
Vector3 norigin = origin;
|
|
double maxdist = 20000.;
|
|
do
|
|
{
|
|
sst.fullstop = true;
|
|
sst.Trace(norigin,level.PointInSector(norigin.xy),x2,maxdist,0,ignore:self);
|
|
maxdist -= (sst.exitpoint-norigin).length();
|
|
norigin = sst.exitpoint;
|
|
x2 = sst.Results.HitVector;
|
|
}
|
|
while ( !sst.fullstop );
|
|
invoker.nkills = 0;
|
|
ProcessTraceHit(sst,origin,x2);
|
|
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 = 320000.;
|
|
if ( invoker.proneme ) fact /= 8.;
|
|
else A_Overlay(-9999,"Jet");
|
|
SWWMUtility.DoKnockback(self,-x,fact);
|
|
}
|
|
action void A_DropCasing()
|
|
{
|
|
let [x, y, z] = SWWMUtility.GetPlayerAxes(self);
|
|
Vector3 origin = SWWMUtility.GetFireOffset(self,10,10,-8);
|
|
let c = Spawn("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()
|
|
{
|
|
let [x, y, z] = SWWMUtility.GetPlayerAxes(self);
|
|
Vector3 origin = SWWMUtility.GetFireOffset(self,10,10,-8);
|
|
MagAmmo ma = MagAmmo(FindInventory("SilverBullets"));
|
|
if ( !ma )
|
|
{
|
|
ma = MagAmmo(Spawn("SilverBullets"));
|
|
ma.Amount = 0;
|
|
ma.AttachToOwner(self);
|
|
}
|
|
if ( ma.Amount < ma.MaxAmount )
|
|
{
|
|
ma.Amount++;
|
|
ma.MagFill();
|
|
}
|
|
else
|
|
{
|
|
let c = Spawn("SilverBullets",origin);
|
|
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](4,8)-(0,0,FRandom[Junk](1,3));
|
|
c.vel += vel*.5;
|
|
}
|
|
if ( !Demolitionist(self) || !(Demolitionist(self).mystats) || swwm_nomapmsg ) return;
|
|
invoker.wastecycle++;
|
|
let s = Demolitionist(self).mystats;
|
|
if ( s.silveregg < 13 )
|
|
{
|
|
if ( invoker.wastecycle < 5 ) return;
|
|
s.silveregg++;
|
|
}
|
|
else return;
|
|
invoker.wastecycle = 0;
|
|
if ( (s.silveregg > 2) && (s.silveregg%2) && (player == players[consoleplayer]) )
|
|
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.WASTE"..1+(((s.silveregg-1)/2)-1));
|
|
}
|
|
action void A_DropMag()
|
|
{
|
|
MagAmmo ma = MagAmmo(FindInventory("SilverBullets"));
|
|
if ( !ma )
|
|
{
|
|
ma = MagAmmo(Spawn("SilverBullets"));
|
|
ma.Amount = 0;
|
|
ma.AttachToOwner(self);
|
|
}
|
|
int maxgiveamt = min(ma.MaxAmount-ma.Amount,invoker.clipcount);
|
|
int dropamt = invoker.clipcount-maxgiveamt;
|
|
if ( dropamt > 0 ) invoker.BufferMagAmmo("SilverBullets",dropamt);
|
|
ma.Amount = min(ma.MaxAmount,ma.Amount+invoker.clipcount);
|
|
ma.MagFill();
|
|
invoker.ClipCount = 0;
|
|
if ( swwm_nomagdrop ) return;
|
|
let [x, y, z] = SWWMUtility.GetPlayerAxes(self);
|
|
Vector3 origin = SWWMUtility.GetFireOffset(self,6,0,-15);
|
|
let c = Spawn("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;
|
|
let [x, y, z] = SWWMUtility.GetPlayerAxes(self);
|
|
vel += x*min(1.,invoker.specialf1)*(600./Mass);
|
|
A_OverlayAlpha(PSP_WEAPON+1,clamp(invoker.specialf1*3.,0.,1.));
|
|
if ( Random[SilverBullet](0,int(invoker.specialf1*2)) )
|
|
self.DamageMobj(invoker,self,1,'jet');
|
|
Vector3 origin = SWWMUtility.GetFireOffset(self,-10,0,-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_LoadMag()
|
|
{
|
|
MagAmmo sb = MagAmmo(FindInventory("SilverBullets"));
|
|
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
else if ( (invoker.Ammo1.Amount <= 0) || (sb.Amount >= sb.ClipSize) )
|
|
{
|
|
int takeamt = min(sb.Amount,sb.ClipSize);
|
|
invoker.clipcount = takeamt;
|
|
sb.Amount -= takeamt;
|
|
int req = invoker.default.ClipCount-invoker.clipcount;
|
|
if ( req > 0 ) invoker.clipcount += invoker.FetchBufferedMagAmmo("SilverBullets",req);
|
|
}
|
|
else if ( invoker.FetchBufferedMagAmmo("SilverBullets",sb.ClipSize,true) )
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
else
|
|
{
|
|
invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1);
|
|
invoker.clipcount = invoker.default.clipcount;
|
|
}
|
|
invoker.wastecycle = 0;
|
|
invoker.ClearBufferedAmmo();
|
|
}
|
|
|
|
override bool PickupForAmmoSWWM( SWWMWeapon ownedWeapon )
|
|
{
|
|
bool good = Super.PickupForAmmoSWWM(ownedWeapon);
|
|
let Owner = ownedWeapon.Owner;
|
|
if ( (AmmoGive1 == 0) && ((clipcount > 0) || chambered) )
|
|
{
|
|
// we were dropped, see if we can add the bullets we contain
|
|
if ( chambered )
|
|
{
|
|
// first check the bullet in the chamber
|
|
let ma = Owner.FindInventory("SilverBullets");
|
|
if ( !ma )
|
|
{
|
|
ma = Inventory(Spawn("SilverBullets"));
|
|
ma.Amount = 0;
|
|
ma.AttachToOwner(Owner);
|
|
}
|
|
if ( ma.Amount >= ma.MaxAmount ) ma.CreateTossable(1);
|
|
ma.Amount++;
|
|
good = true;
|
|
}
|
|
if ( clipcount > 0 )
|
|
{
|
|
let ma = Owner.FindInventory("SilverBullets");
|
|
if ( !ma )
|
|
{
|
|
ma = Inventory(Spawn("SilverBullets"));
|
|
ma.Amount = 0;
|
|
ma.AttachToOwner(Owner);
|
|
}
|
|
int maxgiveamt = min(ma.MaxAmount-ma.Amount,clipcount);
|
|
int dropamt = clipcount-maxgiveamt;
|
|
if ( dropamt > 0 ) ma.CreateTossable(dropamt);
|
|
ma.Amount = min(ma.MaxAmount,ma.Amount+clipcount);
|
|
good = true;
|
|
}
|
|
}
|
|
return good;
|
|
}
|
|
|
|
override void MarkPrecacheSounds()
|
|
{
|
|
Super.MarkPrecacheSounds();
|
|
MarkSound("silverbullet/select");
|
|
MarkSound("silverbullet/deselect");
|
|
MarkSound("silverbullet/meleestart");
|
|
MarkSound("silverbullet/meleeend");
|
|
MarkSound("silverbullet/idle");
|
|
MarkSound("silverbullet/boltopen");
|
|
MarkSound("silverbullet/boltclose");
|
|
MarkSound("silverbullet/magout");
|
|
MarkSound("silverbullet/magin");
|
|
MarkSound("silverbullet/zoomstart");
|
|
MarkSound("silverbullet/zooming");
|
|
MarkSound("silverbullet/zoomend");
|
|
MarkSound("silverbullet/fire1");
|
|
MarkSound("silverbullet/fire2");
|
|
MarkSound("silverbullet/fire3");
|
|
MarkSound("silverbullet/jet");
|
|
MarkSound("silverbullet/casing1");
|
|
MarkSound("silverbullet/casing2");
|
|
MarkSound("silverbullet/casing3");
|
|
MarkSound("silverbullet/casing4");
|
|
MarkSound("silverbullet/mag1");
|
|
MarkSound("silverbullet/mag2");
|
|
MarkSound("silverbullet/mag3");
|
|
MarkSound("silverbullet/hit1");
|
|
MarkSound("silverbullet/hit2");
|
|
MarkSound("silverbullet/flesh1");
|
|
MarkSound("silverbullet/flesh2");
|
|
MarkSound("silverbullet/crouch");
|
|
MarkSound("silverbullet/uncrouch");
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_SILVERBULLET";
|
|
Inventory.Icon "graphics/HUD/Icons/W_SilverBullet.png";
|
|
Inventory.PickupMessage "$T_SILVERBULLET";
|
|
Obituary "$O_SILVERBULLET";
|
|
SWWMWeapon.Tooltip "$TT_SILVERBULLET";
|
|
SWWMWeapon.GetLine "getsilverbullet";
|
|
Weapon.SlotNumber 8;
|
|
Weapon.SelectionOrder 800;
|
|
Weapon.UpSound "silverbullet/select";
|
|
Stamina 400000;
|
|
Weapon.AmmoType1 "SilverBulletAmmo";
|
|
Weapon.AmmoGive1 1;
|
|
SWWMWeapon.DropAmmoType "SWWMCellAmmoSmall";
|
|
SilverBullet.ClipCount 5;
|
|
+SWWMWEAPON.NOFIRSTGIVE;
|
|
+WEAPON.ALT_AMMO_OPTIONAL;
|
|
+WEAPON.EXPLOSIVE;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
Select:
|
|
XZW2 G 2 A_FullRaise();
|
|
XZW2 HIJKLMN 2;
|
|
Goto Ready;
|
|
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;
|
|
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;
|
|
Fire:
|
|
XZW2 A 1
|
|
{
|
|
if ( !invoker.chambered || invoker.fired )
|
|
{
|
|
if ( !invoker.fired && (invoker.clipcount <= 0) && (sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) || (invoker.Ammo1.Amount > 0) || (CountInv("SilverBullets") > 0)) )
|
|
return ResolveState("Reload");
|
|
return ResolveState("AltFire");
|
|
}
|
|
A_SilverFire();
|
|
invoker.fired = true;
|
|
return A_JumpIf(invoker.zoomed,"ZoomFire");
|
|
}
|
|
XZW2 OPQR 2;
|
|
XZW2 STUVW 3;
|
|
XZW2 A 1 A_JumpIf(invoker.specialf1<=0.,"Ready");
|
|
Wait;
|
|
ZoomFire:
|
|
TNT1 A 24;
|
|
TNT1 A 1 A_JumpIf(invoker.specialf1<=0.,"ZoomReady");
|
|
Wait;
|
|
Jet:
|
|
TNT1 A 3
|
|
{
|
|
invoker.specialf1 = 1.5;
|
|
}
|
|
TNT1 A 0
|
|
{
|
|
A_StartSound("silverbullet/jet",CHAN_WEAPON,CHANF_OVERLAP);
|
|
if ( !invoker.zoomed )
|
|
{
|
|
A_Overlay(PSP_WEAPON+1,"JetSmoke");
|
|
A_OverlayFlags(PSP_WEAPON+1,PSPF_RENDERSTYLE|PSPF_ALPHA|PSPF_FORCESTYLE|PSPF_FORCEALPHA,true);
|
|
A_OverlayRenderStyle(PSP_WEAPON+1,STYLE_Add);
|
|
}
|
|
}
|
|
TNT1 A 1
|
|
{
|
|
A_JetCompensate();
|
|
return A_JumpIf(invoker.specialf1<=0.,1);
|
|
}
|
|
Wait;
|
|
TNT1 A 1;
|
|
Stop;
|
|
JetSmoke:
|
|
XZW8 QRS 2;
|
|
XZW8 TUVWX 3;
|
|
XZW8 Y 1 A_JumpIf(invoker.specialf1<=0.,1);
|
|
Wait;
|
|
TNT1 A 1;
|
|
Stop;
|
|
AltFire:
|
|
XZW2 A 0 A_JumpIf(invoker.zoomed,"ZoomCock");
|
|
Goto DoCock;
|
|
ZoomCock:
|
|
TNT1 A 12 A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
TNT1 A 10
|
|
{
|
|
A_QuakeEx(.5,.5,.5,6,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.4);
|
|
A_BumpFOV(.99);
|
|
A_StartSound("silverbullet/boltopen",CHAN_WEAPON,CHANF_OVERLAP);
|
|
if ( invoker.chambered )
|
|
{
|
|
int layer = PSP_WEAPON+2;
|
|
while ( player.FindPSprite(layer) ) layer++;
|
|
if ( invoker.fired ) A_Overlay(layer,"ZoomCasing");
|
|
else A_Overlay(layer,"ZoomBullet");
|
|
}
|
|
if ( !invoker.chambered || invoker.fired ) invoker.wastecycle = 0;
|
|
invoker.fired = false;
|
|
invoker.chambered = (invoker.clipcount>0);
|
|
invoker.clipcount = max(0,invoker.clipcount-1);
|
|
}
|
|
TNT1 A 2
|
|
{
|
|
A_QuakeEx(1.2,1.2,1.2,8,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.65);
|
|
A_BumpFOV(.98);
|
|
A_StartSound("silverbullet/boltclose",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
TNT1 A 20 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
Goto ZoomReady;
|
|
DoCock:
|
|
XZW2 A 2 A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW2 XYZ 2;
|
|
XZW3 AB 2;
|
|
XZW3 C 2
|
|
{
|
|
A_QuakeEx(.5,.5,.5,6,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.4);
|
|
A_BumpFOV(.99);
|
|
A_StartSound("silverbullet/boltopen",CHAN_WEAPON,CHANF_OVERLAP);
|
|
if ( invoker.chambered )
|
|
{
|
|
int layer = PSP_WEAPON+2;
|
|
while ( player.FindPSprite(layer) ) layer++;
|
|
if ( invoker.fired ) A_Overlay(layer,"Casing");
|
|
else A_Overlay(layer,"Bullet");
|
|
}
|
|
if ( !invoker.chambered || invoker.fired ) invoker.wastecycle = 0;
|
|
invoker.fired = false;
|
|
invoker.chambered = (invoker.clipcount>0);
|
|
invoker.clipcount = max(0,invoker.clipcount-1);
|
|
}
|
|
XZW3 DEFG 2;
|
|
XZW3 H 2
|
|
{
|
|
A_QuakeEx(1.2,1.2,1.2,8,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.65);
|
|
A_BumpFOV(.98);
|
|
A_StartSound("silverbullet/boltclose",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZW3 I 2 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW3 JKLMNOPQR 2;
|
|
Goto Ready;
|
|
ZoomCasing:
|
|
TNT1 A 14;
|
|
TNT1 A 0 A_DropCasing();
|
|
Stop;
|
|
ZoomBullet:
|
|
TNT1 A 14;
|
|
TNT1 A 0 A_DropBullet();
|
|
Stop;
|
|
Casing:
|
|
XZW7 S 2
|
|
{
|
|
A_OverlayOffset(OverlayID(),0,0);
|
|
invoker.casex = FRandom[Silverbullet](-2.,2.);
|
|
invoker.casey = FRandom[Silverbullet](-2.,2.);
|
|
}
|
|
XZW7 T 2;
|
|
XZW7 UVWXYZ 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
|
|
XZW8 ABCD 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
|
|
TNT1 A 0 A_DropCasing();
|
|
Stop;
|
|
Bullet:
|
|
XZW8 E 2
|
|
{
|
|
A_OverlayOffset(OverlayID(),0,0);
|
|
invoker.casex = FRandom[Silverbullet](-2.,2.);
|
|
invoker.casey = FRandom[Silverbullet](-2.,2.);
|
|
}
|
|
XZW8 F 2;
|
|
XZW8 GHIJKLMNOP 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
|
|
TNT1 A 0 A_DropBullet();
|
|
Stop;
|
|
Zoom:
|
|
XZW2 A 0 A_JumpIf(invoker.zoomed,"UnZoom");
|
|
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;
|
|
UnZoom:
|
|
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;
|
|
Reload:
|
|
XZW2 A -1
|
|
{
|
|
if ( (invoker.clipcount >= invoker.default.clipcount) || (!sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) && (invoker.Ammo1.Amount <= 0) && (CountInv("SilverBullets") <= 0)) )
|
|
return ResolveState("Idle");
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = ResolveState("Unload");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return ResolveState("Unload");
|
|
}
|
|
Stop;
|
|
Unload:
|
|
XZW2 A 2
|
|
{
|
|
A_PlayerReload();
|
|
A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_ChangeModel("",1,"","",4,"models",String.Format("SilverbulletAmmo%s.png",(invoker.clipcount<=0)?"_Empty":""),CMDL_USESURFACESKIN,-1);
|
|
}
|
|
XZW4 DEFGHI 2;
|
|
XZW4 J 2
|
|
{
|
|
A_BumpView(-2);
|
|
A_BumpFOV(.92);
|
|
A_QuakeEx(1.8,1.8,1.8,8,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.8);
|
|
A_StartSound("silverbullet/magout",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZW4 KLMN 2;
|
|
Goto Load;
|
|
Load:
|
|
XZW4 O 2
|
|
{
|
|
A_DropMag();
|
|
A_ChangeModel("",1,"","",4,"models","SilverbulletAmmo.png",CMDL_USESURFACESKIN,-1);
|
|
}
|
|
XZW4 PQR 2;
|
|
XZW4 S 2
|
|
{
|
|
A_LoadMag();
|
|
A_BumpView(-12);
|
|
A_BumpFOV(.89);
|
|
A_QuakeEx(2.6,2.6,2.6,12,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.2);
|
|
A_StartSound("silverbullet/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
|
}
|
|
XZW4 T 2 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW4 UVWXYZ 2;
|
|
XZW5 ABC 2;
|
|
Goto Ready;
|
|
Idle:
|
|
XZW2 A -1
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = ResolveState("DoIdle");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return ResolveState("DoIdle");
|
|
}
|
|
Stop;
|
|
DoIdle:
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("silverbullet/idle",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerCheckGun();
|
|
}
|
|
XZW5 DEFG 3;
|
|
XZW5 HIJK 2;
|
|
XZW5 LMNO 3;
|
|
XZW5 PQRS 4;
|
|
XZW5 TUVW 3;
|
|
Goto Ready;
|
|
User1:
|
|
XZW2 A -1
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = ResolveState("DoUser1");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return ResolveState("DoUser1");
|
|
}
|
|
Stop;
|
|
DoUser1:
|
|
XZW2 A 2
|
|
{
|
|
A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
|
|
A_PlayerMelee();
|
|
}
|
|
XZW5 XYZ 3 A_BumpAngle(-1,3);
|
|
XZW6 A 1
|
|
{
|
|
A_BumpFOV(.94);
|
|
A_QuakeEx(1.6,1.6,1.6,8,0,15,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.65);
|
|
A_Parry(9);
|
|
}
|
|
XZW6 BC 1 A_BumpAngle(6);
|
|
XZW6 D 1 A_Melee(90,"demolitionist/whitl",1.6,2.,2.,MELEE_Wider);
|
|
XZW6 EF 1 A_BumpAngle(4);
|
|
XZW6 GHI 2 A_BumpAngle(1,2);
|
|
XZW6 J 3 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW6 KLMNO 3;
|
|
XZW6 PQR 2;
|
|
Goto Ready;
|
|
Deselect:
|
|
XZW2 A -1
|
|
{
|
|
if ( invoker.zoomed )
|
|
{
|
|
invoker.dezoomstate = ResolveState("DoDeselect");
|
|
return ResolveState("UnZoom");
|
|
}
|
|
return ResolveState("DoDeselect");
|
|
}
|
|
Stop;
|
|
DoDeselect:
|
|
XZW2 A 2 A_StartSound("silverbullet/deselect",CHAN_WEAPON,CHANF_OVERLAP);
|
|
XZW2 BCDEF 2;
|
|
XZW2 G -1 A_FullLower();
|
|
Stop;
|
|
Flash:
|
|
XZWZ A 2 Bright
|
|
{
|
|
let l = Spawn("SWWMWeaponLight",pos);
|
|
l.args[3] = 200;
|
|
l.target = self;
|
|
}
|
|
Stop;
|
|
}
|
|
}
|