swwmgz_m/zscript/swwm_jackhammer.zsc
Marisa Kirisame aea3a84024 Disallow dropping weapons out of their ready state, prevents exploits/bugs.
Pusher autoswitches to the next weapon after it (skipping the Deep Impact if possible) when thrown, instead of switching to the best weapon, which may have undesirable consequences.
Added icons for weapons and ammo, this doesn't have any actual use yet, but will in the future if I ever implement a custom alt hud.
2020-06-16 00:36:20 +02:00

711 lines
20 KiB
Text

// Tach-Engine Technologies Microfusion Rotary Hammer aka "Pusher" (planned for unreleased Zanaveth Ultra Suite 2)
// Slot 1, replaces Chainsaw, Gauntlets, Timon's Axe
Class PusherImpact : Actor
{
Default
{
Radius 0.1;
Height 0;
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+NOTELEPORT;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_QuakeEx(2,2,2,12,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.3);
A_StartSound("pusher/hit",CHAN_VOICE);
A_SprayDecal("WallCrack",-20);
int numpt = Random[Pusher](4,8);
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8))).unit()*FRandom[Pusher](.1,1.2);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[Pusher](128,192));
}
numpt = Random[Pusher](2,6);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,8);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[Pusher](3,6);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,8);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
Destroy();
}
}
Class BigPusherImpact : Actor
{
Default
{
Radius 0.1;
Height 0;
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+NOTELEPORT;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_QuakeEx(5,5,5,15,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:.8);
A_StartSound("pusher/althit",CHAN_VOICE);
A_SprayDecal("ImpactMark",-20);
int numpt = Random[Pusher](8,16);
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8))).unit()*FRandom[Pusher](.8,2.6);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[Pusher](128,192));
}
numpt = Random[Pusher](4,10);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[Pusher](8,20);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,16);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
Destroy();
}
}
Class PusherProjectile : Actor
{
Vector3 oldvel;
double oldangle, oldpitch;
Actor lasthit;
int hittics;
Default
{
Obituary "$O_PUSHER";
Speed 50;
Radius 10;
Height 10;
DamageFunction int(6*vel.length());
DamageType 'Tenderize';
BounceType "Hexen";
BounceFactor 1.0;
WallBounceFactor 1.0;
Gravity 0.3;
PROJECTILE;
+USEBOUNCESTATE;
+CANBOUNCEWATER;
+INTERPOLATEANGLES;
+DONTBOUNCEONSHOOTABLES;
-BOUNCEAUTOOFF;
+NODAMAGETHRUST;
-BOUNCEONUNRIPPABLES;
-ALLOWBOUNCEONACTORS;
+RIPPER;
-NOGRAVITY;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_StartSound("pusher/fly",CHAN_BODY,CHANF_LOOPING,1.,2.);
A_StartSound("pusher/altfire",CHAN_VOICE);
oldvel = vel;
oldangle = angle;
oldpitch = pitch;
}
void A_Reorient()
{
oldvel = vel;
oldangle = angle;
oldpitch = pitch;
if ( vel.length() <= 0. ) return;
Vector3 dir = vel.unit();
angle += clamp(deltaangle(angle,atan2(dir.y,dir.x)),-2,2);
pitch += clamp(deltaangle(pitch,asin(-dir.z)),-2,2);
// cancel if we hit a wall dead-on
FLineTraceData d;
LineTrace(oldangle,30,oldpitch,TRF_THRUACTORS|TRF_NOSKY,5,data:d);
if ( d.HitType != TRACE_HitNone )
{
angle = oldangle;
pitch = oldpitch;
ClearBounce();
special1 = 1;
ExplodeMissile(BlockingLine,BlockingMobj);
}
}
private bool HitSkyLine( Line l, int hitside )
{
if ( !l ) return false;
// if it's onesided, check if it's a Line_Horizon
if ( !l.sidedef[1] ) return (l.special == Line_Horizon);
Sector outs, ins;
if ( hitside )
{
ins = l.backsector;
outs = l.frontsector;
}
else
{
ins = l.frontsector;
outs = l.backsector;
}
// return true if we're in a sector with sky and we hit the upper part of the line
if ( ins.GetTexture(1) != skyflatnum ) return false;
return (outs.ceilingplane.ZAtPoint(pos.xy) <= pos.z);
}
void A_HandleBounce()
{
Vector3 HitNormal = -vel.unit();
F3DFloor ff;
int lineside = 1;
if ( BlockingFloor )
{
// find closest 3d floor for its normal
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
{
if ( !(CurSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = CurSector.Get3DFloor(i);
break;
}
if ( ff ) HitNormal = -ff.top.Normal;
else HitNormal = BlockingFloor.floorplane.Normal;
}
else if ( BlockingCeiling )
{
// find closest 3d floor for its normal
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
{
if ( !(CurSector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CurSector.Get3DFloor(i);
break;
}
if ( ff ) HitNormal = -ff.bottom.Normal;
else HitNormal = BlockingCeiling.ceilingplane.Normal;
}
else if ( BlockingLine )
{
HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
{
lineside = 0;
HitNormal *= -1;
}
}
else if ( BlockingMobj )
{
Vector3 diff = level.Vec3Diff(pos,BlockingMobj.pos);
if ( (pos.x+radius) <= (BlockingMobj.pos.x-BlockingMobj.radius) )
HitNormal = (-1,0,0);
else if ( (pos.x-radius) >= (BlockingMobj.pos.x+BlockingMobj.radius) )
HitNormal = (1,0,0);
else if ( (pos.y+radius) <= (BlockingMobj.pos.y-BlockingMobj.radius) )
HitNormal = (0,-1,0);
else if ( (pos.y-radius) >= (BlockingMobj.pos.y+BlockingMobj.radius) )
HitNormal = (0,1,0);
else if ( pos.z >= (BlockingMobj.pos.z+BlockingMobj.height) )
HitNormal = (0,0,1);
else if ( (pos.z+height) <= BlockingMobj.pos.z )
HitNormal = (0,0,-1);
}
// undo the bounce, we need to hook in our own
angle = oldangle;
pitch = oldpitch;
vel = oldvel;
// try to guess if we hit the sky
if ( HitSkyLine(BlockingLine,lineside) || (BlockingCeiling && (ceilingpic == skyflatnum)) || (BlockingFloor && (floorpic == skyflatnum)) )
{
special1 = 0;
ExplodeMissile();
return;
}
// re-do the bounce with our formula
vel = .8*((vel dot HitNormal)*HitNormal*(-1.8+FRandom[Pusher](.0,.8))+vel);
A_StartSound("pusher/bounce",volume:.3);
A_AlertMonsters(300);
if ( vel.length() < 5 )
{
special1 = 0;
ExplodeMissile();
}
}
void A_BecomePickup()
{
if ( special1 )
{
// stuff from direct hit
FLineTraceData d;
LineTrace(angle,40,pitch,0,5,data:d);
Vector3 HitNormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
else HitNormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
else HitNormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) HitNormal *= -1;
}
let p = Spawn("BigPusherImpact",d.HitLocation+HitNormal*4);
p.angle = atan2(HitNormal.y,HitNormal.x);
p.pitch = asin(-HitNormal.z);
bNOGRAVITY = true;
}
else pitch = 0;
gravity = 1.;
ClearBounce();
bSPECIAL = true;
A_SetSize(20,16);
A_ChangeLinkFlags(0);
A_StopSound(CHAN_BODY);
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( target == lasthit ) return 0;
lasthit = target;
if ( target.bNOBLOOD || target.bINVULNERABLE ) A_StartSound("pusher/althit",CHAN_WEAPON,CHANF_OVERLAP);
else A_StartSound("pusher/altmeat",CHAN_WEAPON,CHANF_OVERLAP);
target.A_QuakeEx(6,6,6,10,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.7);
SWWMHandler.DoKnockback(target,vel.unit(),85000);
return damage;
}
override void Touch( Actor toucher )
{
let w = toucher.FindInventory("PusherWeapon");
if ( toucher.player && w )
{
let psp = toucher.player.GetPSPrite(PSP_WEAPON);
if ( psp && psp.CurState.InStateSequence(w.FindState("AltMiss")) )
return;
}
if ( !toucher.player || !toucher.GiveInventory("PusherWeapon",1) ) return;
if ( toucher.CheckLocalView() )
{
toucher.A_StartSound("misc/w_pkup",CHAN_ITEM,CHANF_NOPAUSE|CHANF_MAYBE_LOCAL);
let w = toucher.FindInventory("PusherWeapon");
if ( w ) w.PrintPickupMessage(true,w.PickupMessage());
}
else toucher.A_StartSound("misc/w_pkup",CHAN_ITEM,CHANF_MAYBE_LOCAL);
toucher.A_SelectWeapon("PusherWeapon");
Destroy();
}
States
{
Spawn:
XZW1 A 1 A_Reorient();
Wait;
Bounce:
XZW1 A 0 A_HandleBounce();
Goto Spawn;
Death:
XZW1 A 0 A_BecomePickup();
XZW1 A 1 A_JumpIf(pos.z<=floorz,1);
Wait;
XZW1 A -1 A_StartSound("pusher/bounce");
Stop;
}
}
Class PusherWeapon : SWWMWeapon
{
double chargelevel, vibe;
int hitcnt;
transient ui TextureID WeaponBox, ChargeBar;
transient ui DynamicValueInterpolator ChargeInter;
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
{
if ( !WeaponBox ) WeaponBox = TexMan.CheckForTexture("graphics/HUD/PusherDisplay.png",TexMan.Type_Any);
if ( !ChargeBar ) ChargeBar = TexMan.CheckForTexture("graphics/HUD/PusherBar.png",TexMan.Type_Any);
Screen.DrawTexture(WeaponBox,false,bx-60,by-9,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
int chg = clamp(ChargeInter?ChargeInter.GetValue():int(chargelevel*100),0,100);
int cw = int(chg*56./100.);
Screen.DrawTexture(ChargeBar,false,bx-58,by-7,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,cw);
}
override void HudTick()
{
if ( !ChargeInter ) ChargeInter = DynamicValueInterpolator.Create(int(chargelevel*100),.5,1,50);
ChargeInter.Update(int(chargelevel*100));
}
override bool ReportHUDAmmo()
{
return true;
}
action void A_PusherDrill()
{
invoker.chargelevel = clamp(invoker.chargelevel+FRandom[Pusher](-.1,.2),.3,1.);
A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
A_WeaponOffset(FRandom[Pusher](-1,1)*2,32+FRandom[Pusher](-1,1)*2);
A_ZoomFactor(1.01,ZOOM_INSTANT);
A_ZoomFactor(1.);
A_Recoil(-cos(pitch));
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
FLineTraceData d;
LineTrace(angle,60,pitch,TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
if ( d.HitType != TRACE_HitNone )
{
A_QuakeEx(3,3,3,7,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
A_AlertMonsters(1200);
int dmg = int(10+invoker.chargelevel*5);
if ( d.HitType == TRACE_HitActor )
{
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
self.angle += clamp(diff,-5.,5.);
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,8500);
d.HitActor.A_QuakeEx(4,4,4,10,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.1);
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Tenderize',DMG_THRUSTLESS);
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
{
let p = Spawn("PusherImpact",d.HitLocation-d.HitDir*4);
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
p.pitch = asin(d.HitDir.z);
}
else
{
d.HitActor.TraceBleed(dmg,invoker);
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
d.HitActor.A_StartSound("pusher/meat",CHAN_DAMAGE,CHANF_OVERLAP);
}
// move towards target
bJUSTATTACKED = true;
}
else
{
Vector3 HitNormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
else HitNormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
else HitNormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) HitNormal *= -1;
d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation+HitNormal*4);
}
let p = Spawn("PusherImpact",d.HitLocation+HitNormal*4);
p.angle = atan2(HitNormal.y,HitNormal.x);
p.pitch = asin(-HitNormal.z);
}
}
int numpt = Random[Pusher](1,3);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("SWWMViewSmoke",origin);
SWWMViewSmoke(s).ofs = (10,2,-3);
s.target = self;
s.special1 = 1;
s.scale *= 1.4;
s.alpha *= .03;
}
if ( swwm_extraalert || !(invoker.hitcnt%20) ) A_AlertMonsters(500);
invoker.hitcnt++;
}
action void A_PusherAlt()
{
A_StopSound(CHAN_WEAPON);
if ( IsActorPlayingSound(CHAN_WEAPONEXTRA,"pusher/motor") )
A_StartSound("pusher/motorend",CHAN_WEAPONEXTRA,CHANF_DEFAULT,pitch:1.5);
A_StartSound("pusher/stop",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/altfire",CHAN_WEAPON,CHANF_OVERLAP);
A_ZoomFactor(1.+invoker.chargelevel*.2,ZOOM_INSTANT);
A_ZoomFactor(1.);
A_Recoil(-(2.+4.*invoker.chargelevel)*cos(pitch));
A_QuakeEx(2+int(invoker.chargelevel*2),2+int(invoker.chargelevel*2),2+int(invoker.chargelevel*2),3+int(invoker.chargelevel*6),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.3+invoker.chargelevel*.7);
A_WeaponOffset(0,32);
A_Overlay(-9999,null);
A_PlayerFire();
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
FLineTraceData d;
LineTrace(angle,80,pitch,TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
bool gone = false;
if ( d.HitType != TRACE_HitNone )
{
A_QuakeEx(8,8,8,12,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
A_AlertMonsters(1600);
int dmg = int(300*invoker.chargelevel);
if ( d.HitType == TRACE_HitActor )
{
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
self.angle += clamp(diff,-5.,5.);
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,85000);
d.HitActor.A_QuakeEx(9,9,9,15,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.1);
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Tenderize',DMG_THRUSTLESS);
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
{
let p = Spawn("BigPusherImpact",d.HitLocation-d.HitDir*4);
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
p.pitch = asin(d.HitDir.z);
}
else
{
d.HitActor.TraceBleed(dmg,invoker);
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
d.HitActor.A_StartSound("pusher/altmeat",CHAN_DAMAGE,CHANF_OVERLAP);
}
}
else
{
Vector3 HitNormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
else HitNormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
else HitNormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) HitNormal *= -1;
d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation+HitNormal*4);
}
let p = Spawn("BigPusherImpact",d.HitLocation+HitNormal*4);
p.angle = atan2(HitNormal.y,HitNormal.x);
p.pitch = asin(-HitNormal.z);
}
}
else if ( !Random[Pusher](0,3-int(invoker.chargelevel*3)) )
{
// didn't hit anything, randomly slip off
player.SetPSprite(PSP_WEAPON,ResolveState("AltMiss"));
A_StopSound(CHAN_WEAPON);
A_StopSound(CHAN_WEAPONEXTRA);
let p = Spawn("PusherProjectile",origin);
p.angle = angle;
p.pitch = pitch;
p.vel = x*p.speed*invoker.chargelevel;
p.target = self;
SWWMHandler.DoKnockback(self,x,85000.);
}
if ( !gone )
{
int numpt = Random[Pusher](3,5);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("SWWMViewSmoke",origin);
SWWMViewSmoke(s).ofs = (10,2,-3);
s.target = self;
s.special1 = 2;
s.scale *= 1.4;
s.alpha *= .1;
}
}
A_AlertMonsters(1200);
invoker.chargelevel = 0.;
}
action void A_BeginCharge()
{
invoker.chargelevel = invoker.vibe = 0.;
A_WeaponOffset(0,32);
A_QuakeEx(1,1,1,33,0,1,"",QF_RELATIVE|QF_SCALEUP,rollIntensity:.5);
A_Overlay(-9999,"Dummy");
}
action void A_ChargeUp()
{
invoker.chargelevel = min(1.,invoker.chargelevel+.035);
if ( invoker.chargelevel >= .5 ) invoker.vibe = min(1.,invoker.vibe+.02);
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
int numpt = Random[Pusher](3,5);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("SWWMViewSmoke",origin);
SWWMViewSmoke(s).ofs = (10,2,-3);
s.target = self;
s.special1 = 1;
s.scale *= 1.4;
s.alpha *= .1*(invoker.chargelevel-invoker.vibe);
}
A_WeaponOffset(FRandom[Pusher](-1,1)*(invoker.chargelevel-invoker.vibe),32+FRandom[Pusher](-1,1)*(invoker.chargelevel-invoker.vibe));
if ( !(player.cmd.buttons&BT_ALTATTACK) && (invoker.chargelevel > .3) )
player.SetPSprite(PSP_WEAPON,ResolveState("AltRelease"));
}
Default
{
Tag "$T_PUSHER";
Inventory.PickupMessage "$I_PUSHER";
Obituary "$O_PUSHER";
Inventory.Icon "graphics/HUD/Icons/W_Pusher.png";
Weapon.UpSound "pusher/select";
Weapon.SlotNumber 1;
Weapon.SelectionOrder 2800;
Stamina 10000;
}
States
{
Spawn:
XZW1 A -1;
Stop;
Select:
XZW2 G 2 A_FullRaise();
XZW2 HIJKL 2;
Goto Ready;
Ready:
XZW2 A 1 A_WeaponReady(WRF_ALLOWRELOAD|WRF_ALLOWZOOM|WRF_ALLOWUSER1);
Wait;
Fire:
XZW2 A 2
{
A_WeaponOffset(0,32);
invoker.chargelevel = .2;
invoker.hitcnt = 0;
A_StartSound("pusher/start",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/motor",CHAN_WEAPONEXTRA,CHANF_LOOPING,pitch:1.5);
}
XZW2 M 2;
XZW2 N 0 A_StartSound("pusher/drill",CHAN_WEAPON,CHANF_LOOPING);
Hold:
XZW2 N 1
{
A_WeaponOffset(FRandom[Pusher](-1,1),32+FRandom[Pusher](-1,1));
A_Recoil(cos(pitch));
}
XZW2 O 1 A_PusherDrill();
XZW2 P 1
{
A_WeaponOffset(FRandom[Pusher](-1,1),32+FRandom[Pusher](-1,1));
A_Recoil(cos(pitch));
}
XZW2 Q 1 A_PusherDrill();
XZW2 R 1
{
A_WeaponOffset(FRandom[Pusher](-1,1),32+FRandom[Pusher](-1,1));
A_Recoil(cos(pitch));
}
XZW2 S 1 A_PusherDrill();
XZW2 N 2
{
if ( player.cmd.buttons&BT_ATTACK )
return ResolveState("Hold");
invoker.chargelevel *= .4;
A_Recoil(.5*cos(pitch));
A_ClearRefire();
A_WeaponOffset(0,32);
A_StopSound(CHAN_WEAPON);
A_StartSound("pusher/stop",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/motorend",CHAN_WEAPONEXTRA,CHANF_DEFAULT,pitch:1.5);
return ResolveState(null);
}
XZW2 T 2 { invoker.chargelevel = 0.; }
Goto Ready;
Dummy:
TNT1 A 1 A_ChargeUp();
Wait;
AltFire:
XZW2 A 2
{
A_StartSound("pusher/start",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/motor",CHAN_WEAPONEXTRA,CHANF_LOOPING,pitch:1.5);
A_StartSound("pusher/pullback",CHAN_WEAPON,CHANF_OVERLAP);
}
XZW2 UVW 2;
XZW2 X 0 A_BeginCharge();
XZW2 XYZ 3;
XZW3 ABCDEFG 3;
XZW3 H 0
{
A_QuakeEx(1,1,1,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
A_StartSound("pusher/motorend",CHAN_WEAPONEXTRA,CHANF_DEFAULT,pitch:1.5);
}
XZW3 H 3;
Wait;
AltRelease:
#### # 1 A_PusherAlt();
XZW5 R 2;
XZW3 IJKL 2;
XZW3 MNOP 3;
Goto Ready;
AltMiss:
XZW3 QRSTUVW 1;
TNT1 A -1
{
let nw = player.mo.PickNextWeapon();
// gross hack (don't prioritize Deep Impact if we have something better than it)
if ( nw is 'DeepImpact' )
{
player.ReadyWeapon = nw;
nw = player.mo.PickNextWeapon();
player.ReadyWeapon = invoker;
}
if ( nw != invoker ) player.PendingWeapon = nw;
RemoveInventory(invoker);
}
Stop;
Reload:
Zoom:
XZW2 A 2
{
A_StartSound("pusher/checkout",CHAN_WEAPON,CHANF_OVERLAP);
A_PlayerCheckGun();
}
XZW3 XYZ 2;
XZW4 ABCDEFGHIJKLMNOPQR 2;
XZW4 STUVWXYZ 3;
Goto Ready;
User1:
XZW2 A 2
{
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
A_PlayerMelee();
}
XZW5 ABC 2;
XZW5 D 1 A_Parry(9);
XZW5 EFGH 1;
XZW5 I 0 A_Melee(70,"demolitionist/whitl",1.1);
XZW5 IJ 2;
XZW5 K 2 { invoker.PlayUpSound(self); }
XZW5 LM 2;
XZW5 NOPQ 3;
Goto Ready;
Deselect:
XZW2 B 2 A_StartSound("pusher/deselect",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 CDEF 2;
XZW2 F -1 A_FullLower();
Stop;
}
}