Class UShells : Ammo { Default { Tag "$T_SHELLS"; Inventory.Icon "I_ShotSh"; Inventory.PickupMessage ""; Inventory.Amount 12; Inventory.MaxAmount 48; Ammo.BackpackAmount 6; Ammo.BackpackMaxAmount 96; Ammo.DropAmount 6; } override String PickupMessage() { if ( PickupMsg.Length() > 0 ) return Super.PickupMessage(); return String.Format("%s%d%s",StringTable.Localize("$I_SHELLSL"),Amount,StringTable.Localize("$I_SHELLSR")); } override bool TryPickup( in out Actor toucher ) { if ( !sting_proto ) return false; // not allowed return Super.TryPickup(toucher); } override void Tick() { Super.Tick(); if ( sting_proto ) return; if ( !Owner ) { let r = Spawn((GetClass()=="UShells")?"ShellBox":"Shells",pos,ALLOW_REPLACE); r.spawnangle = spawnangle; r.spawnpoint = spawnpoint; r.angle = angle; r.pitch = pitch; r.roll = roll; r.special = special; r.args[0] = args[0]; r.args[1] = args[1]; r.args[2] = args[2]; r.args[3] = args[3]; r.args[4] = args[4]; r.ChangeTid(tid); r.SpawnFlags = SpawnFlags&~MTF_SECRET; r.HandleSpawnFlags(); r.SpawnFlags = SpawnFlags; r.bCountSecret = SpawnFlags&MTF_SECRET; r.vel = vel; r.master = master; r.target = target; r.tracer = tracer; r.bDropped = bDropped; r.bNeverRespawn = bNeverRespawn; } else Owner.RemoveInventory(self); Destroy(); } States { Spawn: QAMO A -1; Stop; } } Class UShells2 : UShells { Default { Tag "$T_SHELLS2"; Inventory.Amount 4; Ammo.DropAmount 4; +INVENTORY.IGNORESKILL; } } Class QCasing : UCasing { Default { BounceSound "quadshot/shell"; } override void PostBeginPlay() { Super.PostBeginPlay(); heat = 0.; // no smoke } } Class QuadshotTracer : LineTracer { Actor ignoreme; Array ShootThroughList; Array hitlist; override ETraceStatus TraceCallback() { if ( Results.HitType == TRACE_HitActor ) { if ( Results.HitActor == ignoreme ) return TRACE_Skip; if ( Results.HitActor.bSHOOTABLE ) { int amt = FlakAccumulator.GetAmount(Results.HitActor); // getgibhealth isn't clearscope, fuck int gibhealth = -int(Results.HitActor.GetSpawnHealth()*gameinfo.gibfactor); if ( Results.HitActor.GibHealth != int.min ) gibhealth = -abs(Results.HitActor.GibHealth); // if gibbed, go through without dealing more damage if ( Results.HitActor.health-amt <= gibhealth ) return TRACE_Skip; let ent = new("HitListEntry"); ent.hitactor = Results.HitActor; ent.hitlocation = Results.HitPos; ent.x = Results.HitVector; hitlist.Push(ent); // go right on through if dead if ( Results.HitActor.health-amt <= 0 ) return TRACE_Skip; // stap return TRACE_Abort; } 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; ShootThroughList.Push(Results.HitLine); return TRACE_Skip; } return TRACE_Stop; } } Class QuadShot : UnrealWeapon { int ClipCount, HeldShells; bool ClipOut; QuadshotTracer t; property ClipCount : ClipCount; override bool TryPickup( in out Actor toucher ) { if ( !sting_proto ) return false; // not allowed return Super.TryPickup(toucher); } override void Tick() { Super.Tick(); if ( sting_proto ) return; if ( !Owner ) { let r = Spawn("Shotgun",pos,ALLOW_REPLACE); r.spawnangle = spawnangle; r.spawnpoint = spawnpoint; r.angle = angle; r.pitch = pitch; r.roll = roll; r.special = special; r.args[0] = args[0]; r.args[1] = args[1]; r.args[2] = args[2]; r.args[3] = args[3]; r.args[4] = args[4]; r.ChangeTid(tid); r.SpawnFlags = SpawnFlags&~MTF_SECRET; r.HandleSpawnFlags(); r.SpawnFlags = SpawnFlags; r.bCountSecret = SpawnFlags&MTF_SECRET; r.vel = vel; r.master = master; r.target = target; r.tracer = tracer; r.bDropped = bDropped; r.bNeverRespawn = bNeverRespawn; } else Owner.RemoveInventory(self); Destroy(); } override int, int, bool, bool GetClipAmount() { return ClipOut?-1:ClipCount, -1, (ClipCount<2), false; } action void ProcessTraceHit( QuadshotTracer t, Vector3 origin, Vector3 dir, int bc = 1 ) { for ( int i=0; i 0 ) { player.SetPSprite(PSP_WEAPON,invoker.FindState("Reload")); return true; } else if ( bDryFire ) { player.SetPSprite(PSP_WEAPON,invoker.FindState("DryFire")); return true; } } return false; } 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_QUADSHOT"; Inventory.PickupMessage "$I_QUADSHOT"; Weapon.UpSound "quadshot/select"; Weapon.SlotNumber 3; Weapon.SelectionOrder 1400; Weapon.SlotPriority 0.9; Weapon.AmmoType "UShells"; Weapon.AmmoUse 1; Weapon.AmmoType2 "UShells"; Weapon.AmmoUse2 1; Weapon.AmmoGive 20; Weapon.Kickback 320; UTWeapon.DropAmmo 10; QuadShot.ClipCount 4; } States { Spawn: QSPK A -1; Stop; QSPK B -1; Stop; Select: QUAS A 1 A_Raise(int.max); Wait; Ready: QUAS A 0 { invoker.clipout = false; invoker.clipcount += invoker.heldshells; invoker.heldshells = 0; } QUAS ABCDEFGHIJK 2 A_WeaponReady(WRF_NOFIRE); Goto Idle; Dummy: TNT1 A 1 { A_CheckReload(); if ( !A_QuadshotCheckForReload() ) { let weap = Weapon(invoker); if ( (invoker.clipcount < invoker.default.clipcount) && (invoker.Ammo1.Amount > 0) ) A_WeaponReady(WRF_ALLOWRELOAD); else A_WeaponReady(); } } Wait; Idle: QUAI A 0 A_Overlay(-9999,"Dummy"); QUAI A 50; QUAI A 0 A_Jump(40,"Twiddle"); Goto Idle+1; Twiddle: #### # 2; QUAT ABCDEFGHIJKLMNOPQRSTU 2; Goto Idle+1; Fire: #### # 1 { if ( !A_QuadshotCheckForReload(true) ) { A_Overlay(-9999,"Null"); A_QuadshotFire(); } } QUAF ABCDEFGHIJK 1; Goto Pump; DryFire: #### # 1 { A_Overlay(-9999,"Null"); A_PlaySound("automag/click",CHAN_WEAPON,Dampener.Active(self)?.05:.5); } QUAF AJK 2; Goto Idle; AltFire: #### # 1 { if ( !A_QuadshotCheckForReload(true) ) { A_Overlay(-9999,"Null"); A_QuadshotFire(true); } } QUAA ABCDEFGHIJKLMNOPQRS 1; Goto Idle; Pump: QUAP A 0 { if ( self is 'UTPlayer' ) UTPlayer(self).PlayReloading(); } QUAP ABCD 1; QUAP E 0 A_PlaySound("quadshot/pump1",CHAN_6,Dampener.Active(self)?.1:1.); QUAP EFGHIJKLM 1; QUAP N 0 A_PlaySound("quadshot/pump2",CHAN_6,Dampener.Active(self)?.1:1.); QUAP NOPQRSTUVWXYZ[\ 1; QUAP \ 0; QUAI A 0; // force no tween Goto Idle; Reload: QUAR A 0 A_Overlay(-9999,"Null"); QUAR ABCDEFGHIJK 1; QUAR L 0 { A_PlaySound("quadshot/open",CHAN_6,Dampener.Active(self)?.1:1.); if ( self is 'UTPlayer' ) UTPlayer(self).PlayAttacking3(); } QUAR LMNOPQRSTU 1; QUAR V 0 { invoker.clipout = true; A_DropShells(); let weap = Weapon(invoker); } QUAR VWXYZ[\] 1; QUR2 ABCDEFGHIJKLMNOPQR 1; QUR2 S 0 { invoker.clipout = false; invoker.heldshells = invoker.clipcount; invoker.clipcount = 0; A_PlaySound("quadshot/load",CHAN_6,Dampener.Active(self)?.1:1.); let weap = Weapon(invoker); for ( int i=0; i<2; i++ ) { if ( (invoker.clipcount >= 4) || (invoker.heldshells+weap.Ammo1.Amount <= 0) ) continue; invoker.clipcount++; if ( invoker.heldshells > 0 ) invoker.heldshells--; else if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) weap.Ammo1.Amount--; } if ( self is 'UTPlayer' ) UTPlayer(self).PlayReloading(); } QUR2 STUVWXYZ[\] 1; QUR3 ABCDEFGHIJKLMNO 1; QUR3 P 0 { A_PlaySound("quadshot/load",CHAN_6,Dampener.Active(self)?.1:1.); let weap = Weapon(invoker); for ( int i=0; i<2; i++ ) { if ( (invoker.clipcount >= 4) || (invoker.heldshells+weap.Ammo1.Amount <= 0) ) continue; invoker.clipcount++; if ( invoker.heldshells > 0 ) invoker.heldshells--; else if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) weap.Ammo1.Amount--; } if ( self is 'UTPlayer' ) UTPlayer(self).PlayReloading(); } QUR3 PQRSTUVWXYZ[\] 1; QUR4 ABCDE 1; QUR4 F 0 { A_PlaySound("quadshot/close",CHAN_6,Dampener.Active(self)?.1:1.); if ( self is 'UTPlayer' ) UTPlayer(self).PlayAttacking3(); } QUR4 FGHIJKLMNOPQ 1; Goto Idle; Deselect: #### # 1 A_Overlay(-9999,"Null"); QUAD ABCDEFG 1; QUAD G 1 A_Lower(int.max); Wait; MuzzleFlash: QFLA A 3 Bright { let l = Spawn("EnforcerLight",pos); l.target = self; } Stop; MuzzleFlashAlt: QFLA B 3 Bright { let l = Spawn("EnforcerLight",pos); l.target = self; l.args[3] += 20; } Stop; } }