swwmgz_m/zscript/weapons/swwm_thiccboolet.zsc

1526 lines
46 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_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
{
bool pastwall, fullstop;
Array<WallPenetrate> WallPenetrateList;
Vector3 exitpoint;
transient Array<F3DFloor> ffloors; // needs to be done like this because HAHA SCOPE
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;
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_HasHitSky )
{
fullstop = true;
return TRACE_Stop;
}
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<ffloors.Size(); j++ )
{
if ( ffloors[j].target != s ) continue;
double minz = ffloors[j].bottom.ZAtPoint(ofs.xy);
double maxz = ffloors[j].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);
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 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 SilverBullet : SWWMWeapon
{
bool chambered, fired;
bool fcbchambered, fcbloaded, fcbselected;
ui int lastammo;
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 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 HudTick()
{
Super.HudTick();
if ( !ZoomInter ) ZoomInter = SmoothDynamicValueInterpolator.Create(zoomlevel*10,.5);
ZoomInter.Update(zoomlevel*10);
if ( lastammo && (lastammo != fcbselected+1) && (Owner.player == players[consoleplayer]) )
{
let bar = SWWMStatusBar(statusbar);
if ( bar )
{
bar.ntagstr = StringTable.Localize(fcbselected?"$SWWM_FCBSEL":"$SWWM_XSBSEL");
bar.ntagtic = level.totaltime;
bar.ntagcol = nametagcolor;
}
}
lastammo = fcbselected+1;
}
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 IsCurrentAmmo( Class<Ammo> kind )
{
if ( fcbselected ) return (kind is AmmoType2);
return (kind is AmmoType1);
}
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) || (Ammo2.Amount > 0) || (Owner.CountInv("SilverBullets") > 0) || (Owner.CountInv("SilverBullets2") > 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 ( zoomed ) crosshair = 99;
if ( !Owner || !Owner.player )
{
proneme = false;
lookscale = 1.;
return;
}
if ( (Owner.player.ReadyWeapon == self) && Owner.player.onground )
{
if ( Owner.player.cmd.buttons&BT_CROUCH )
{
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",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 PPShader.SetEnabled("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_Impact);
t.ShootThroughList[i].Activate(self,0,SPAC_PCross);
}
for ( int i=0; i<t.WaterHitList.Size(); i++ )
{
let b = Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
b.target = self;
b.A_CheckTerrain();
}
for ( int i=0; i<t.HitList.Size(); i++ )
{
if ( !t.HitList[i].HitActor ) continue;
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),t.Hitlist[i].HitDamage*20.*FRandom[SilverBullet](.8,1.2));
let p = SWWMPuff.Setup(t.HitList[i].HitLocation,t.HitList[i].x,invoker,self,t.HitList[i].HitActor);
int dmg = t.HitList[i].HitActor.DamageMobj(p,self,t.Hitlist[i].HitDamage,'Sniped',DMG_FOILINVUL|DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
if ( t.HitList[i].HitActor && (t.HitList[i].HitActor.Health <= 0) && (t.HitList[i].HitActor.bIsMonster || t.HitList[i].HitActor.player) && t.HitList[i].HitActor.IsHostile(self) )
{
invoker.nkills++;
SWWMUtility.AchievementProgress("conga",invoker.nkills,player);
if ( t.Hitlist[i].pastwall ) SWWMUtility.AchievementProgressInc("thruwall",1,player);
}
if ( t.HitList[i].HitActor && !t.HitList[i].HitActor.bNOBLOOD && !t.HitList[i].HitActor.bDORMANT )
{
t.HitList[i].HitActor.TraceBleed(dmg,self);
t.HitList[i].HitActor.SpawnBlood(t.HitList[i].HitLocation,atan2(t.HitList[i].x.y,t.HitList[i].x.x)+180,dmg);
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;
p.master = invoker;
p.bAMBUSH = t.HitList[i].pastwall;
}
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;
p.master = invoker;
p.bAMBUSH = t.HitList[i].pastwall;
}
}
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;
p.master = invoker;
p.bAMBUSH = t.WallPenetrateList[i].pastwall;
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;
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 )
{
if ( s )
{
s.SetOrigin(level.Vec3Offset(origin,dir*i),false);
s.Explode();
continue;
}
s = SilverAirRip(Spawn("SilverAirRip",level.Vec3Offset(start,tdir*i)));
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 = Spawn("SWWMHalfSmoke",ofs);
b.Scale *= FRandom[Boolet](.9,1.6);
b.alpha *= .5;
b.special1 = Random[Boolet](0,2);
}
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 )
{
if ( s )
{
s.SetOrigin(level.Vec3Offset(start,tdir*j),false);
s.Explode(true);
continue;
}
s = SilverAirRip(Spawn("SilverAirRip",level.Vec3Offset(start,tdir*j)));
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 = Spawn("SWWMHalfSmoke",ofs);
b.Scale *= FRandom[Boolet](.9,1.6);
b.alpha *= .5;
b.special1 = Random[Boolet](0,2);
}
}
}
else
{
SilverAirRip s;
for ( int i=0; i<t.Results.Distance; i+=16 )
{
if ( s )
{
s.SetOrigin(level.Vec3Offset(origin,dir*i),false);
s.Explode();
continue;
}
s = SilverAirRip(Spawn("SilverAirRip",level.Vec3Offset(origin,dir*i)));
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 = Spawn("SWWMHalfSmoke",ofs);
b.Scale *= FRandom[Boolet](.9,1.6);
b.alpha *= .5;
b.special1 = Random[Boolet](0,2);
}
}
}
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);
t.ShootThroughList[i].Activate(self,0,SPAC_Impact);
}
for ( int i=0; i<t.WaterHitList.Size(); i++ )
{
let b = Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
b.target = self;
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 = invoker.proneme?800:600;
// might as well apply explosion on top
if ( dmg >= t.Results.HitActor.Health ) dmg += 600;
let p = SWWMPuff.Setup(t.Results.HitPos,t.Results.HitVector,invoker,self,t.Results.HitActor);
dmg = t.Results.HitActor.DamageMobj(p,self,dmg,'Explodium',DMG_FOILINVUL|DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
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?1400:1200,self,t.Results.HitVector,t.Results.HitPos.z);
}
SilverAirRip s;
for ( int i=0; i<t.Results.Distance; i+=16 )
{
if ( s )
{
s.SetOrigin(level.Vec3Offset(origin,dir*i),false);
s.Explode();
continue;
}
s = SilverAirRip(Spawn("SilverAirRip2",level.Vec3Offset(origin,dir*i)));
s.target = self;
s.Explode();
}
}
override Vector3 GetTraceOffset( int index )
{
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|QF_3D,rollIntensity:str/4.);
double basezoom = invoker.zoomed?clamp(invoker.zoomlevel,1.,16.):1.;
A_BumpFOV(invoker.fcbchambered?.8:.76);
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?1200.:1000.;
sst.hitlist.Clear();
sst.shootthroughlist.Clear();
sst.waterhitlist.Clear();
sst.wallpenetratelist.Clear();
sst.ffloors.Clear();
for ( int i=0; i<level.Sectors.Size(); i++ )
{
Sector s = level.Sectors[i];
for ( int j=0; j<s.Get3DFloorCount(); j++ )
{
F3DFloor ff = s.Get3DFloor(j);
if ( ff.flags&(F3DFloor.FF_EXISTS|F3DFloor.FF_SOLID) )
sst.ffloors.Push(ff);
}
}
sst.pastwall = false;
Vector3 norigin = origin;
double maxdist = 20000.;
do
{
sst.fullstop = true;
sst.Trace(norigin,level.PointInSector(norigin.xy),x2,maxdist,TRACE_HitSky);
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 = 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;
}
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] )
Console.MidPrint(null,"swwmsilverbulleteasteregg"..((s.silveregg-1)/2));
}
action void A_DropMag()
{
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 ) invoker.BufferMagAmmo(mac,dropamt);
ma.Amount = min(ma.MaxAmount,ma.Amount+invoker.clipcount);
ma.MagFill();
invoker.ClipCount = 0;
if ( swwm_nomagdrop ) return;
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+1,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|WRF_NOSWITCH);
}
action void A_AltHold()
{
A_WeaponReady(WRF_NOFIRE|WRF_NOSWITCH);
// 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"));
}
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();
}
action void A_LoadMagAlt()
{
MagAmmo sb = MagAmmo(FindInventory("SilverBullets2"));
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
invoker.clipcount = invoker.default.clipcount;
else if ( (invoker.Ammo2.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("SilverBullets2",req);
}
else if ( invoker.FetchBufferedMagAmmo("SilverBullets2",sb.ClipSize,true) )
invoker.clipcount = invoker.default.clipcount;
else
{
invoker.Ammo2.Amount = max(0,invoker.Ammo2.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
Class<Inventory> wammo = fcbchambered?'SilverBullets2':'SilverBullets';
let ma = Owner.FindInventory(wammo);
if ( !ma )
{
ma = Inventory(Spawn(wammo));
ma.Amount = 0;
ma.AttachToOwner(Owner);
}
if ( ma.Amount >= ma.MaxAmount ) ma.CreateTossable(1);
ma.Amount++;
good = true;
}
if ( clipcount > 0 )
{
Class<Inventory> wammo = fcbloaded?'SilverBullets2':'SilverBullets';
let ma = Owner.FindInventory(wammo);
if ( !ma )
{
ma = Inventory(Spawn(wammo));
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/altfire1");
MarkSound("silverbullet/altfire2");
MarkSound("silverbullet/altfire3");
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/chode1");
MarkSound("silverbullet/chode2");
MarkSound("silverbullet/crouch");
MarkSound("silverbullet/uncrouch");
}
Default
{
Tag "$T_SILVERBULLET";
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;
Weapon.AmmoType2 "SilverBulletAmmo2";
Weapon.AmmoGive2 0;
SWWMWeapon.DropAmmoType "SWWMCellAmmoSmall";
SilverBullet.ClipCount 5;
+SWWMWEAPON.NOFIRSTGIVE;
+WEAPON.ALT_AMMO_OPTIONAL;
+WEAPON.EXPLOSIVE;
Radius 36;
Height 36;
}
States
{
Spawn:
XZW1 A -1 NoDelay A_JumpIf(invoker.fcbloaded,1);
XZW1 B -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+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:
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 ) return ResolveState("ZoomCock");
return invoker.fcbloaded?ResolveState("DoCock2"):ResolveState("DoCock");
}
ZoomCock:
TNT1 A 12 A_StartSound("silverbullet/meleestart",CHAN_WEAPON,CHANF_OVERLAP);
TNT1 A 10
{
A_StartSound("silverbullet/boltopen",CHAN_WEAPON,CHANF_OVERLAP);
if ( invoker.chambered )
{
int layer = PSP_WEAPON+2;
while ( player.FindPSprite(layer) ) layer++;
if ( invoker.fired )
{
if ( invoker.fcbchambered ) A_Overlay(layer,"ZoomCasing2");
else A_Overlay(layer,"ZoomCasing");
}
else
{
if ( invoker.fcbchambered ) A_Overlay(layer,"ZoomBullet2");
else A_Overlay(layer,"ZoomBullet");
}
}
if ( !invoker.chambered || invoker.fired ) invoker.wastecycle = 0;
invoker.fired = false;
invoker.chambered = (invoker.clipcount>0);
if ( invoker.clipcount > 0 ) invoker.fcbchambered = invoker.fcbloaded;
invoker.clipcount = max(0,invoker.clipcount-1);
}
TNT1 A 2 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_StartSound("silverbullet/boltopen",CHAN_WEAPON,CHANF_OVERLAP);
if ( invoker.chambered )
{
int layer = PSP_WEAPON+2;
while ( player.FindPSprite(layer) ) layer++;
if ( invoker.fired )
{
if ( invoker.fcbchambered ) A_Overlay(layer,"Casing2");
else A_Overlay(layer,"Casing");
}
else
{
if ( invoker.fcbchambered ) A_Overlay(layer,"Bullet2");
else A_Overlay(layer,"Bullet");
}
}
if ( !invoker.chambered || invoker.fired ) invoker.wastecycle = 0;
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 )
{
int layer = PSP_WEAPON+2;
while ( player.FindPSprite(layer) ) layer++;
if ( invoker.fired )
{
if ( invoker.fcbchambered ) A_Overlay(layer,"Casing2");
else A_Overlay(layer,"Casing");
}
else
{
if ( invoker.fcbchambered ) A_Overlay(layer,"Bullet2");
else A_Overlay(layer,"Bullet");
}
}
if ( !invoker.chambered || invoker.fired ) invoker.wastecycle = 0;
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;
ZoomCasing:
TNT1 A 14;
TNT1 A 0 A_DropCasing();
Stop;
ZoomCasing2:
TNT1 A 14;
TNT1 A 0 A_DropCasing(true);
Stop;
ZoomBullet:
TNT1 A 14;
TNT1 A 0 A_DropBullet();
Stop;
ZoomBullet2:
TNT1 A 14;
TNT1 A 0 A_DropBullet(true);
Stop;
Casing:
XZW7 D 2
{
A_OverlayOffset(OverlayID(),0,0);
invoker.casex = FRandom[Silverbullet](-2.,2.);
invoker.casey = FRandom[Silverbullet](-2.,2.);
}
XZW7 E 2;
XZW7 FGHIJKLMNO 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
TNT1 A 0 A_DropCasing();
Stop;
Casing2:
XZWD D 2
{
A_OverlayOffset(OverlayID(),0,0);
invoker.casex = FRandom[Silverbullet](-2.,2.);
invoker.casey = FRandom[Silverbullet](-2.,2.);
}
XZWD E 2;
XZWD FGHIJKLMNO 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
TNT1 A 0 A_DropCasing(true);
Stop;
Bullet:
XZWD P 2
{
A_OverlayOffset(OverlayID(),0,0);
invoker.casex = FRandom[Silverbullet](-2.,2.);
invoker.casey = FRandom[Silverbullet](-2.,2.);
}
XZWD Q 2;
XZWD RSTUVWXYZ 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
XZWE A 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
TNT1 A 0 A_DropBullet();
Stop;
Bullet2:
XZWE B 2
{
A_OverlayOffset(OverlayID(),0,0);
invoker.casex = FRandom[Silverbullet](-2.,2.);
invoker.casey = FRandom[Silverbullet](-2.,2.);
}
XZWE C 2;
XZWE DEFGHIJKLM 1 A_OverlayOffset(OverlayID(),invoker.casex,invoker.casey,WOF_ADD|WOF_INTERPOLATE);
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
{
// autoswitch if needed
A_SwitchAmmoType(true);
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;
A_LoadMag();
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;
A_LoadMagAlt();
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,2.,2.,MELEE_Wider);
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,2.,2.,MELEE_Wider);
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;
}
}