Class ImpalerAmmo : Ammo { Default { Tag "$T_IMPAMMO"; Inventory.Icon "I_Impale"; Inventory.PickupMessage "$T_IMPAMMO"; Inventory.Amount 3; Inventory.MaxAmount 15; Ammo.BackpackAmount 3; Ammo.BackpackMaxAmount 30; Ammo.DropAmount 3; +INVENTORY.IGNORESKILL; } States { Spawn: IAMO A -1; Stop; } } Class ImpalerAmmo2 : ImpalerAmmo { Default { Tag "$T_IMPAMMO2"; Inventory.PickupMessage "$T_IMPAMMO2"; Inventory.Amount 1; Ammo.DropAmount 1; +INVENTORY.IGNORESKILL; } } Class ImpalerChunk : StingerChunk { override void Tick() { Super.Tick(); if ( isFrozen() ) return; let c = Spawn("UTSmoke",pos); c.vel = vel*.3; c.SetShade(Color(4,1,3)*Random[Impaler](48,63)); c.bBRIGHT = true; c.alpha *= .5*alpha; c.scale *= .5*scale.x; } } Class ImpalerBurstLight : PaletteLight { Default { Tag "ImpExpl"; Args 0,0,0,50; ReactionTime 15; } } Class ImpalerProjectile : Actor { Default { Obituary "$O_IMPALER1"; DamageType 'Impaler'; Speed 30; Radius 4; Height 4; PROJECTILE; +SKYEXPLODE; +EXPLODEONWATER; +FORCERADIUSDMG; +NODAMAGETHRUST; } action void A_ImpalerHit() { bFORCEXYBILLBOARD = true; scale *= 2.+special1*0.01; A_AlertMonsters(); A_SetRenderStyle(1.,STYLE_Add); A_NoGravity(); A_Explode(90+special1,120+special1/2); UTMainHandler.DoBlast(self,120+special1/2,40000); A_QuakeEx(2,2,2,5,0,250+special1/2,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120+special1/2,rollintensity:0.2); A_PlaySound("impaler/hit",CHAN_VOICE); A_SprayDecal("WallCrack",20); Spawn("ImpalerBurstLight",pos); double ang, pt; int numpt = Random[Impaler](4,8); for ( int i=0; i= (d.HitActor.pos.z+d.HitActor.height*0.8) ) dmg = d.HitActor.DamageMobj(invoker,self,dmg*2,'Decapitated',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); else dmg = d.HitActor.DamageMobj(invoker,self,dmg,'slashed',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); UTMainHandler.DoKnockback(d.HitActor,d.HitDir,12000); if ( d.HitActor.player ) d.HitActor.A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25); if ( !d.HitActor.bNOBLOOD ) { d.HitActor.TraceBleed(dmg,invoker); d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg); } } else if ( d.HitType == TRACE_HitWall ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation-d.HitDir*4); A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12); if ( !d.HitActor || d.HitActor.bNOBLOOD ) { A_PlaySound("impaler/wall",CHAN_WEAPON); let p = Spawn("SawImpact",d.HitLocation-d.HitDir*4); p.angle = atan2(d.HitDir.y,d.HitDir.x); p.pitch = asin(-d.HitDir.z); } else A_PlaySound("impaler/flesh",CHAN_WEAPON); A_AlertMonsters(); A_QuakeEx(1,1,1,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.06); return true; } return false; } action void A_Stab() { UTMainHandler.DoSwing(self,(FRandom[Impaler](-1,1),FRandom[Impaler](-1,1)),0.3,-0.2,2,SWING_Spring,0,2); for ( int i=0; i<8; i++ ) if ( TryHit(angle+i*(45./16),15) || TryHit(angle-i*(45./16),15) ) return; } override void DoEffect() { Super.DoEffect(); if ( Owner.player.ReadyWeapon != self ) return; if ( (Owner.waterlevel > 2) && !(level.maptime%5) ) ClipCount = max(0,ClipCount-1); let psp = Owner.player.FindPSprite(-2); if ( psp ) psp.alpha = clamp(ClipCount/double(default.ClipCount),0.,1.); } override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount ) { if ( ClipCount > 0 ) return true; return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount); } Default { Tag "$T_IMPALER"; Inventory.PickupMessage "$I_IMPALER"; Weapon.UpSound "impaler/select"; Weapon.SlotNumber 7; Weapon.SelectionOrder 0; Weapon.SlotPriority 0.9; Weapon.AmmoType "ImpalerAmmo"; Weapon.AmmoUse 1; Weapon.AmmoType2 "ImpalerAmmo"; Weapon.AmmoUse2 1; Weapon.AmmoGive 6; UTWeapon.DropAmmo 3; Impaler.ClipCount 30; } States { Spawn: IMPP A -1; Stop; IMPP B -1; Stop; Select: IMPS A 1 A_Raise(int.max); Wait; Ready: IMPS ABCDEF 3 A_WeaponReady(WRF_NOFIRE); IMPI A 0 { let weap = Weapon(invoker); invoker.HasGem = false; if ( (invoker.ClipCount>=0) || (weap.Ammo1.Amount > 0) ) return ResolveState("Reload"); return ResolveState("Idle"); } Goto Idle; Dummy: TNT1 A 1 { let weap = Weapon(invoker); int flags = 0; if ( weap.Ammo1.Amount > 0 ) flags |= WRF_ALLOWRELOAD; if ( invoker.HasGem && (invoker.ClipCount <= 0) ) flags |= WRF_NOSECONDARY; A_WeaponReady(flags); } Wait; Idle: IMPI A 0 A_Overlay(-9999,"Dummy"); IMPI ABCDEFGH 10; Goto Idle+1; Melee: IMPM A 2 { A_Overlay(-9999,"Null"); A_PlaySound("impaler/stab",CHAN_WEAPON); } IMPM BC 2; IMPM D 2 A_Stab(); IMPM EFGHIJ 2; Goto Idle; Fire: IMPF A 0 { if ( !invoker.HasGem ) return ResolveState("Melee"); A_ImpalerFire(); return ResolveState(null); } IMPF ABCDEFGHI 2; IMPI A 0 A_JumpIfNoAmmo("Idle"); Goto Reload; AltFire: IMPA A 0 { if ( !invoker.HasGem ) return ResolveState("Melee"); A_Overlay(-9999,"Null"); A_Overlay(-3,"GemAltFire"); A_Overlay(-2,"ZapAltFire"); A_PlaySound("impaler/altfire",CHAN_WEAPON,looping:true); return ResolveState(null); } IMPA ABCDEFGH 2; Goto AltHold; AltHold: IMPA IJKLMNOP 2; Goto AltRelease; AltRelease: IMPA Q 0 { A_Overlay(-3,"GemAltRelease"); A_Overlay(-2,"ZapAltRelease"); A_PlaySound("impaler/gem",CHAN_WEAPON,looping:true); } IMPA QRSTUVWX 2; Goto Idle; Reload: IMPG A 0 { A_Overlay(-9999,"Null"); invoker.HasGem = !invoker.HasGem; if ( invoker.HasGem ) { let weap = Weapon(invoker); if ( invoker.ClipCount < 0 ) { weap.DepleteAmmo(false,true,1); invoker.ClipCount = invoker.default.ClipCount; } A_Overlay(-3,"GemUp"); A_Overlay(-2,"ZapUp"); A_OverlayFlags(-2,PSPF_RenderStyle|PSPF_Alpha,true); A_OverlayRenderStyle(-2,STYLE_Add); A_PlaySound("impaler/gem",CHAN_WEAPON,looping:true); } else { A_Overlay(-3,"GemDown"); A_Overlay(-2,"ZapDown"); A_PlaySound("impaler/gemdown",CHAN_WEAPON); } if ( self is 'UTPlayer' ) UTPlayer(self).PlayReloading(); } IMPG ABCDE 2; Goto Idle; Deselect: IMPD A 0 A_Overlay(-9999,"Null"); IMPD A 0 A_JumpIf(!invoker.HasGem,"FullDeselect"); IMPG A 0 { invoker.HasGem = false; A_Overlay(-3,"GemDown"); A_Overlay(-2,"ZapDown"); A_PlaySound("impaler/gemdown",CHAN_WEAPON); } IMPG ABCDE 2; Goto FullDeselect; FullDeselect: IMPD ABCDEF 2; IMPD F 1 A_Lower(int.max); Wait; GemUp: IMGS ABCDE 2; Goto GemIdle; GemIdle: IMGI ABCDEFGH 10; Loop; GemDown: IMGD ABCDE 2; Stop; GemAltFire: IMGA ABCDEFGH 2; Goto GemAltHold; GemAltHold: IMGA IJKLMNOP 2; Loop; GemAltRelease: IMGA QRSTUVWX 2; Goto GemIdle; ZapUp: IMZS ABCDE 2 Bright; Goto ZapIdle; ZapIdle: IMZI ABCDEFGH 10 Bright; Loop; ZapDown: IMZD ABCDE 2 Bright; Stop; ZapAltFire: IMZA ABCDEFGH 2 Bright; Goto ZapAltHold; ZapAltHold: IMZA IJKLMNOP 2 Bright; Loop; ZapAltRelease: IMZA QRSTUVWX 2 Bright; Goto ZapIdle; MuzzleFlash: IMFF A 3 Bright { let l = Spawn("ImpalerLight",pos); l.target = self; } Stop; } }