diff --git a/GunLore.md b/GunLore.md index c8485cb..2f740cf 100644 --- a/GunLore.md +++ b/GunLore.md @@ -219,16 +219,16 @@ A very rare prototype handgun. Due to the difficulty of its manufacture, it was quickly discontinued and not many of these exist. You would have to be pretty lucky to come across one. -Both of its fire modes work exactly like the Automag, although due to -internal differences, it fires much slower, but bullets come out at a much -higher velocity, resulting in increased damage. - The special trait of this weapon comes into play when you realize that there's no need to reload. An experimental entanglement unit inside the gun's internal mag locates spare ammunition carried by the user and automatically loads it. -Since there's no need to reload, pressing the reload button makes use of the -gun's weight to beat the crap out of your enemies up close. +Both of its fire modes work exactly like the Automag, although due to +internal differences, it's a bit weaker in terms of speed and damage. The fact +that it never needs to reload at least compensates for this. + +Pressing the reload button makes use of the gun's weight to beat the crap out +of your enemies up close. As an added bonus, you can press the zoom button to spin the gun. This doesn't serve any purpose other than looking cool. diff --git a/Readme.md b/Readme.md index 09a0a28..7a8e0b7 100644 --- a/Readme.md +++ b/Readme.md @@ -30,6 +30,8 @@ Doom Tournament (currently the devel branch is required). - Restored flashlight - Minigun (slot 0) (replaces chaingun) - SMP 7243 (slot 0) (replaces bfg9000) + - Protomag (slot 2) (replaces pistol) + - Dual Protomags - Quadshot (slot 3) (replaces shotguns) - Backpack (replaces backpack, identical to Doom Tournament version) - Unreal 1 HUD @@ -65,8 +67,6 @@ Doom Tournament (currently the devel branch is required). - Razorclaw (slot 1) (replaces chainsaw) - Teleport Capsules (slot 1) - - Protomag (slot 2) (replaces pistol) - - Dual Protomags - Stunner (slot 4) (replaces chainsaw) - Fireblaster (slot 5) (replaces rocket launcher) - Flamethrower (slot 6) (replaces plasma rifle) diff --git a/modeldef.betamag b/modeldef.betamag index ad31de5..0aab251 100644 --- a/modeldef.betamag +++ b/modeldef.betamag @@ -13,3 +13,412 @@ Model "Betamag" ROTATING FrameIndex AUTP A 1 0 } + +Model "BCasing" +{ + Path "models" + Model 0 "OldShell_d.3d" + Skin 0 "AutoHand1.png" + Scale 0.0264 -0.022 0.022 + AngleOffset 90 + RollOffset 180 + ZOffset 1 + USEACTORPITCH + USEACTORROLL + DONTCULLBACKFACES + USEROTATIONCENTER + Rotation-Center 0 0 1 + + FrameIndex PCAS A 0 0 +} +Model "BCasing2" +{ + Path "models" + Model 0 "OldShell_d.3d" + Skin 0 "Autom1.png" + Scale 0.0264 -0.022 0.022 + AngleOffset 90 + RollOffset 180 + ZOffset 1 + USEACTORPITCH + USEACTORROLL + DONTCULLBACKFACES + USEROTATIONCENTER + Rotation-Center 0 0 1 + + FrameIndex PCAS A 0 0 +} + +Model "Betamag" +{ + Path "models" + Model 3 "Flat_d.3d" + Skin 3 "OldMuz.png" + AngleOffset 90 + Offset 12 -30 -2.5 + Scale 0.06 0.06 0.06 + + PitchOffset 0 + FrameIndex AMZ1 A 3 0 + PitchOffset 90 + FrameIndex AMZ1 B 3 0 + PitchOffset 180 + FrameIndex AMZ1 C 3 0 + PitchOffset 270 + FrameIndex AMZ1 D 3 0 + + Offset 6 -30 -10 + + PitchOffset 0 + FrameIndex AMZ2 A 3 0 + PitchOffset 90 + FrameIndex AMZ2 B 3 0 + PitchOffset 180 + FrameIndex AMZ2 C 3 0 + PitchOffset 270 + FrameIndex AMZ2 D 3 0 + + Offset -12 -30 -2.5 + + PitchOffset 0 + FrameIndex AMZ3 A 3 0 + PitchOffset 90 + FrameIndex AMZ3 B 3 0 + PitchOffset 180 + FrameIndex AMZ3 C 3 0 + PitchOffset 270 + FrameIndex AMZ3 D 3 0 + + Offset -6 -30 -10 + + PitchOffset 0 + FrameIndex AMZ4 A 3 0 + PitchOffset 90 + FrameIndex AMZ4 B 3 0 + PitchOffset 180 + FrameIndex AMZ4 C 3 0 + PitchOffset 270 + FrameIndex AMZ4 D 3 0 +} + +Model "Betamag" +{ + Path "models" + Model 0 "OldAutoMag_d.3d" + SurfaceSkin 0 0 "AutoHand1.png" + SurfaceSkin 0 1 "Automa1.png" + Scale 0.12 -0.06 0.084 + Offset 10.2 -17 -8.7 + AngleOffset 90 + RollOffset -90 + + // Down + FrameIndex AUTD A 0 0 + FrameIndex AUTD B 0 1 + FrameIndex AUTD C 0 2 + FrameIndex AUTD D 0 3 + FrameIndex AUTD E 0 4 + FrameIndex AUTD F 0 5 + FrameIndex AUTD G 0 6 + // Select + FrameIndex AUTS A 0 6 + FrameIndex AUTS B 0 7 + FrameIndex AUTS C 0 8 + FrameIndex AUTS D 0 9 + FrameIndex AUTS E 0 10 + FrameIndex AUTS F 0 11 + FrameIndex AUTS G 0 12 + FrameIndex AUTS H 0 13 + FrameIndex AUTS I 0 14 + FrameIndex AUTS J 0 15 + FrameIndex AUTS K 0 16 + // Idle + FrameIndex AUTI A 0 17 + FrameIndex AUTI B 0 18 + FrameIndex AUTI C 0 19 + FrameIndex AUTI D 0 20 + FrameIndex AUTI E 0 21 + FrameIndex AUTI F 0 22 + // Twiddle + FrameIndex AUTT A 0 23 + FrameIndex AUTT B 0 24 + FrameIndex AUTT C 0 25 + FrameIndex AUTT D 0 26 + FrameIndex AUTT E 0 27 + FrameIndex AUTT F 0 28 + FrameIndex AUTT G 0 29 + FrameIndex AUTT H 0 30 + FrameIndex AUTT I 0 31 + FrameIndex AUTT J 0 32 + FrameIndex AUTT K 0 33 + FrameIndex AUTT L 0 34 + FrameIndex AUTT M 0 35 + FrameIndex AUTT N 0 36 + FrameIndex AUTT O 0 37 + FrameIndex AUTT P 0 38 + FrameIndex AUTT Q 0 39 + // Fire + FrameIndex AUTF A 0 40 + FrameIndex AUTF B 0 41 + FrameIndex AUTF C 0 42 + FrameIndex AUTF D 0 43 + FrameIndex AUTF E 0 44 + FrameIndex AUTF F 0 45 + FrameIndex AUTF G 0 46 + FrameIndex AUTF H 0 47 + FrameIndex AUTF I 0 48 + FrameIndex AUTF J 0 49 + // T1 + FrameIndex AUTA A 0 50 + FrameIndex AUTA B 0 51 + FrameIndex AUTA C 0 52 + FrameIndex AUTA D 0 53 + FrameIndex AUTA E 0 54 + // AltFire + FrameIndex AUTA F 0 55 + FrameIndex AUTA G 0 56 + FrameIndex AUTA H 0 57 + FrameIndex AUTA I 0 58 + FrameIndex AUTA J 0 59 + FrameIndex AUTA K 0 60 + FrameIndex AUTA L 0 61 + // T2 + FrameIndex AUTA M 0 62 + FrameIndex AUTA N 0 63 + FrameIndex AUTA O 0 64 + FrameIndex AUTA P 0 65 + FrameIndex AUTA Q 0 66 + // Twirl + FrameIndex AUTR A 0 67 + FrameIndex AUTR B 0 68 + FrameIndex AUTR C 0 69 + FrameIndex AUTR D 0 70 + FrameIndex AUTR E 0 71 + FrameIndex AUTR F 0 72 + FrameIndex AUTR G 0 73 + FrameIndex AUTR H 0 74 + FrameIndex AUTR I 0 75 + FrameIndex AUTR J 0 76 + FrameIndex AUTR K 0 77 + FrameIndex AUTR L 0 78 + FrameIndex AUTR M 0 79 + FrameIndex AUTR N 0 80 + // TwirlLoop + FrameIndex AUTR O 0 81 + FrameIndex AUTR P 0 82 + FrameIndex AUTR Q 0 83 + FrameIndex AUTR R 0 84 + FrameIndex AUTR S 0 85 + FrameIndex AUTR T 0 86 + FrameIndex AUTR U 0 87 + FrameIndex AUTR V 0 88 + FrameIndex AUTR W 0 89 + FrameIndex AUTR X 0 90 + // TwirlEnd + FrameIndex AUTR Y 0 91 + FrameIndex AUTR Z 0 92 + FrameIndex AUTR [ 0 93 + FrameIndex AUTR \ 0 94 + FrameIndex AUTR ] 0 95 + FrameIndex AUR2 A 0 96 + FrameIndex AUR2 B 0 97 + FrameIndex AUR2 C 0 98 + FrameIndex AUR2 D 0 99 + FrameIndex AUR2 E 0 100 + FrameIndex AUR2 F 0 101 + FrameIndex AUR2 G 0 102 + FrameIndex AUR2 H 0 103 + FrameIndex AUR2 I 0 104 + FrameIndex AUR2 J 0 105 + FrameIndex AUR2 K 0 106 + // Whip + FrameIndex AUTW A 0 107 + FrameIndex AUTW B 0 108 + FrameIndex AUTW C 0 109 + FrameIndex AUTW D 0 110 + FrameIndex AUTW E 0 111 + FrameIndex AUTW F 0 112 + FrameIndex AUTW G 0 113 + FrameIndex AUTW H 0 114 + FrameIndex AUTW I 0 115 + FrameIndex AUTW J 0 116 + FrameIndex AUTW K 0 117 + FrameIndex AUTW L 0 118 + FrameIndex AUTW M 0 119 + FrameIndex AUTW N 0 120 + FrameIndex AUTW O 0 121 + FrameIndex AUTW P 0 122 + FrameIndex AUTW Q 0 123 + FrameIndex AUTW R 0 124 + FrameIndex AUTW S 0 125 + FrameIndex AUTW T 0 126 + FrameIndex AUTW U 0 127 + FrameIndex AUTW V 0 128 + FrameIndex AUTW W 0 129 + FrameIndex AUTW X 0 130 + FrameIndex AUTW Y 0 131 + FrameIndex AUTW Z 0 132 + FrameIndex AUTW [ 0 133 + FrameIndex AUTW \ 0 134 +} + +Model "Betamag" +{ + Path "models" + Model 2 "OldAutoMag_d.3d" + SurfaceSkin 2 0 "Autom1.png" + SurfaceSkin 2 1 "Automa1.png" + Scale 0.12 0.06 0.084 + Offset -10.2 -17 -8.7 + AngleOffset -90 + RollOffset -90 + + // Down + FrameIndex 2UTD A 2 0 + FrameIndex 2UTD B 2 1 + FrameIndex 2UTD C 2 2 + FrameIndex 2UTD D 2 3 + FrameIndex 2UTD E 2 4 + FrameIndex 2UTD F 2 5 + FrameIndex 2UTD G 2 6 + // Select + FrameIndex 2UTS A 2 6 + FrameIndex 2UTS B 2 7 + FrameIndex 2UTS C 2 8 + FrameIndex 2UTS D 2 9 + FrameIndex 2UTS E 2 10 + FrameIndex 2UTS F 2 11 + FrameIndex 2UTS G 2 12 + FrameIndex 2UTS H 2 13 + FrameIndex 2UTS I 2 14 + FrameIndex 2UTS J 2 15 + FrameIndex 2UTS K 2 16 + // Idle + FrameIndex 2UTI A 2 17 + FrameIndex 2UTI B 2 18 + FrameIndex 2UTI C 2 19 + FrameIndex 2UTI D 2 20 + FrameIndex 2UTI E 2 21 + FrameIndex 2UTI F 2 22 + // Twiddle + FrameIndex 2UTT A 2 23 + FrameIndex 2UTT B 2 24 + FrameIndex 2UTT C 2 25 + FrameIndex 2UTT D 2 26 + FrameIndex 2UTT E 2 27 + FrameIndex 2UTT F 2 28 + FrameIndex 2UTT G 2 29 + FrameIndex 2UTT H 2 30 + FrameIndex 2UTT I 2 31 + FrameIndex 2UTT J 2 32 + FrameIndex 2UTT K 2 33 + FrameIndex 2UTT L 2 34 + FrameIndex 2UTT M 2 35 + FrameIndex 2UTT N 2 36 + FrameIndex 2UTT O 2 37 + FrameIndex 2UTT P 2 38 + FrameIndex 2UTT Q 2 39 + // Fire + FrameIndex 2UTF A 2 40 + FrameIndex 2UTF B 2 41 + FrameIndex 2UTF C 2 42 + FrameIndex 2UTF D 2 43 + FrameIndex 2UTF E 2 44 + FrameIndex 2UTF F 2 45 + FrameIndex 2UTF G 2 46 + FrameIndex 2UTF H 2 47 + FrameIndex 2UTF I 2 48 + FrameIndex 2UTF J 2 49 + // T1 + FrameIndex 2UTA A 2 50 + FrameIndex 2UTA B 2 51 + FrameIndex 2UTA C 2 52 + FrameIndex 2UTA D 2 53 + FrameIndex 2UTA E 2 54 + // AltFire + FrameIndex 2UTA F 2 55 + FrameIndex 2UTA G 2 56 + FrameIndex 2UTA H 2 57 + FrameIndex 2UTA I 2 58 + FrameIndex 2UTA J 2 59 + FrameIndex 2UTA K 2 60 + FrameIndex 2UTA L 2 61 + // T2 + FrameIndex 2UTA M 2 62 + FrameIndex 2UTA N 2 63 + FrameIndex 2UTA O 2 64 + FrameIndex 2UTA P 2 65 + FrameIndex 2UTA Q 2 66 + // Twirl + FrameIndex 2UTR A 2 67 + FrameIndex 2UTR B 2 68 + FrameIndex 2UTR C 2 69 + FrameIndex 2UTR D 2 70 + FrameIndex 2UTR E 2 71 + FrameIndex 2UTR F 2 72 + FrameIndex 2UTR G 2 73 + FrameIndex 2UTR H 2 74 + FrameIndex 2UTR I 2 75 + FrameIndex 2UTR J 2 76 + FrameIndex 2UTR K 2 77 + FrameIndex 2UTR L 2 78 + FrameIndex 2UTR M 2 79 + FrameIndex 2UTR N 2 80 + // TwirlLoop + FrameIndex 2UTR O 2 81 + FrameIndex 2UTR P 2 82 + FrameIndex 2UTR Q 2 83 + FrameIndex 2UTR R 2 84 + FrameIndex 2UTR S 2 85 + FrameIndex 2UTR T 2 86 + FrameIndex 2UTR U 2 87 + FrameIndex 2UTR V 2 88 + FrameIndex 2UTR W 2 89 + FrameIndex 2UTR X 2 90 + // TwirlEnd + FrameIndex 2UTR Y 2 91 + FrameIndex 2UTR Z 2 92 + FrameIndex 2UTR [ 2 93 + FrameIndex 2UTR \ 2 94 + FrameIndex 2UTR ] 2 95 + FrameIndex 2UR2 A 2 96 + FrameIndex 2UR2 B 2 97 + FrameIndex 2UR2 C 2 98 + FrameIndex 2UR2 D 2 99 + FrameIndex 2UR2 E 2 100 + FrameIndex 2UR2 F 2 101 + FrameIndex 2UR2 G 2 102 + FrameIndex 2UR2 H 2 103 + FrameIndex 2UR2 I 2 104 + FrameIndex 2UR2 J 2 105 + FrameIndex 2UR2 K 2 106 + // Whip + FrameIndex 2UTW A 2 107 + FrameIndex 2UTW B 2 108 + FrameIndex 2UTW C 2 109 + FrameIndex 2UTW D 2 110 + FrameIndex 2UTW E 2 111 + FrameIndex 2UTW F 2 112 + FrameIndex 2UTW G 2 113 + FrameIndex 2UTW H 2 114 + FrameIndex 2UTW I 2 115 + FrameIndex 2UTW J 2 116 + FrameIndex 2UTW K 2 117 + FrameIndex 2UTW L 2 118 + FrameIndex 2UTW M 2 119 + FrameIndex 2UTW N 2 120 + FrameIndex 2UTW O 2 121 + FrameIndex 2UTW P 2 122 + FrameIndex 2UTW Q 2 123 + FrameIndex 2UTW R 2 124 + FrameIndex 2UTW S 2 125 + FrameIndex 2UTW T 2 126 + FrameIndex 2UTW U 2 127 + FrameIndex 2UTW V 2 128 + FrameIndex 2UTW W 2 129 + FrameIndex 2UTW X 2 130 + FrameIndex 2UTW Y 2 131 + FrameIndex 2UTW Z 2 132 + FrameIndex 2UTW [ 2 133 + FrameIndex 2UTW \ 2 134 +} diff --git a/models/OldAutoMag_a.3d b/models/OldAutoMag_a.3d index d80bbcc..b4bae33 100644 Binary files a/models/OldAutoMag_a.3d and b/models/OldAutoMag_a.3d differ diff --git a/models/OldAutoMag_d.3d b/models/OldAutoMag_d.3d index 0c7e28c..4909b3b 100644 Binary files a/models/OldAutoMag_d.3d and b/models/OldAutoMag_d.3d differ diff --git a/models/OldAutomag.blend b/models/OldAutomag.blend index 1dd04d0..24f5ea5 100644 Binary files a/models/OldAutomag.blend and b/models/OldAutomag.blend differ diff --git a/sndinfo.txt b/sndinfo.txt index ac95f36..ec92e42 100644 --- a/sndinfo.txt +++ b/sndinfo.txt @@ -249,6 +249,12 @@ quadshot/shell5 qshell5 quadshot/shell6 qshell6 $random quadshot/shell { quadshot/shell1 quadshot/shell2 quadshot/shell3 quadshot/shell4 quadshot/shell5 quadshot/shell6 } +betamag/select oldasel +betamag/fire oldmag +betamag/slide oldmage +betamag/whip oldawhip +betamag/hit oldahit + translator/event transa3 detector/start detact diff --git a/zscript/betamag.zsc b/zscript/betamag.zsc index a5d3137..1dbed99 100644 --- a/zscript/betamag.zsc +++ b/zscript/betamag.zsc @@ -1,5 +1,271 @@ +Class BCasing : UTCasing +{ +} +Class BCasing2 : UTCasing +{ +} + Class Betamag : UnrealWeapon { + bool SlaveActive, SlaveDown, SlaveAltFire, SlaveWhip, SlaveSpin; + int SlaveRefire; + double AltAccuracy; + + override bool HandlePickup( Inventory item ) + { + if ( sting_protomags && (item.GetClass() == GetClass()) ) + { + SetTag(StringTable.Localize("$T_PROTOMAG2")); + return Super.HandlePickup(item); + } + return Super.HandlePickup(item); + } + override String PickupMessage() + { + if ( Owner ) return Super.PickupMessage(); + return StringTable.Localize("$I_PROTOMAG2"); + } + override Inventory CreateTossable( int amt ) + { + Inventory inv = Super.CreateTossable(amt); + if ( inv ) + { + SetTag(StringTable.Localize("$T_PROTOMAG")); + inv.SetTag(StringTable.Localize("$T_PROTOMAG")); + if ( Owner && (Owner.player.ReadyWeapon == self) ) + { + // delete the slave overlay + PSprite psp; + for ( psp = Owner.player.psprites; psp; psp = psp.next ) + { + if ( (psp.Caller == self) && ((psp.id == 2) || (psp.id == -9998)) ) psp.Destroy(); + slaveactive = false; + slavedown = false; + } + } + } + return inv; + } + action void A_BetamagRefire( statelabel flash = null, bool slave = false ) + { + Weapon weap = Weapon(invoker); + if ( !weap || !player ) return; + if ( invoker.altaccuracy < 0.1 ) invoker.altaccuracy += 0.015; + if ( slave ) + { + if ( weap.Ammo1.Amount <= 0 ) + { + invoker.slaverefire = 0; + return; + } + bool pending = (player.PendingWeapon != WP_NOCHANGE) && (player.WeaponState & WF_REFIRESWITCHOK); + if ( (player.cmd.buttons&BT_ATTACK) && !invoker.slavealtfire && !pending && (player.health > 0) ) + { + invoker.slaverefire++; + if ( player.ReadyWeapon.CheckAmmo(Weapon.PrimaryFire,true) ) + player.setpsprite(2,flash?ResolveState(flash):ResolveState("LeftHold")); + } + else if ( (player.cmd.buttons&BT_ALTATTACK) && invoker.slavealtfire && !pending && (player.health > 0) ) + { + invoker.slaverefire++; + if ( player.ReadyWeapon.CheckAmmo(Weapon.AltFire,true) ) + player.setpsprite(2,flash?ResolveState(flash):ResolveState("LeftAltHold")); + } + else + { + invoker.slaverefire = 0; + player.ReadyWeapon.CheckAmmo(invoker.slavealtfire?Weapon.AltFire:Weapon.PrimaryFire,true); + } + } + else + { + if ( weap.Ammo1.Amount <= 0 ) + { + A_ClearRefire(); + return; + } + A_Refire(flash); + } + } + action void A_LeftWeaponReady() + { + Weapon weap = Weapon(invoker); + if ( !weap || !player ) return; + if ( weap.Ammo1.Amount <= 0 ) return; + if ( player.cmd.buttons&BT_ATTACK && !player.ReadyWeapon.bAltFire ) + { + invoker.slaverefire = 0; + invoker.slavealtfire = false; + player.setpsprite(2,ResolveState("LeftFire")); + } + else if ( player.cmd.buttons&BT_ALTATTACK && player.ReadyWeapon.bAltFire ) + { + invoker.slaverefire = 0; + invoker.slavealtfire = true; + player.setpsprite(2,ResolveState("LeftAltFire")); + } + } + private action bool TryWhip( double angle ) + { + FTranslatedLineTarget t; + double slope = AimLineAttack(angle,DEFMELEERANGE,t,0.,ALF_CHECK3D); + FLineTraceData d; + LineTrace(angle,DEFMELEERANGE,slope,0,player.viewheight,data:d); + if ( d.HitType != TRACE_HitNone ) + { + if ( d.HitType == TRACE_HitActor ) + { + int dmg = Random[Betamag](1,10)<<1; + dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Melee',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); + UTMainHandler.DoKnockback(d.HitActor,d.HitDir,35000); + 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); + A_PlaySound("betamag/hit",CHAN_WEAPON); + A_AlertMonsters(); + return true; + } + return false; + } + action void A_BetamagWhip() + { + invoker.FireEffect(); + for ( int i=0; i<16; i++ ) if ( TryWhip(angle+i*(45./16)) || TryWhip(angle-i*(45./16)) ) return; + } + action void A_BetamagFire( bool alt = false, bool slave = false ) + { + Weapon weap = Weapon(invoker); + if ( !weap ) return; + if ( weap.Ammo1.Amount <= 0 ) return; + if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; + invoker.FireEffect(); + UTMainHandler.DoFlash(self,Color(32,255,128,0),1); + A_PlaySound("betamag/fire",slave?CHAN_6:CHAN_WEAPON,!Dampener.Active(self)?1.:.2); + if ( !Dampener.Active(self) ) A_AlertMonsters(); + A_QuakeEx(2,2,2,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08); + if ( slave ) + { + if ( alt ) A_Overlay(-3,"LeftAltMuzzleFlash"); + else A_Overlay(-3,"LeftMuzzleFlash"); + A_OverlayFlags(-3,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true); + A_OverlayRenderstyle(-3,STYLE_Add); + UTMainHandler.DoSwing(self,(FRandom[Betamag](0.5,0.2),FRandom[Betamag](-0.3,0.2)),2,0,1,SWING_Spring,0,2); + } + else + { + if ( alt ) A_Overlay(-2,"AltMuzzleFlash"); + else A_Overlay(-2,"MuzzleFlash"); + A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true); + A_OverlayRenderstyle(-2,STYLE_Add); + UTMainHandler.DoSwing(self,(FRandom[Betamag](-0.2,-0.5),FRandom[Betamag](-0.3,0.2)),2,0,1,SWING_Spring,0,2); + } + Vector3 x, y, z, x2, y2, z2; + [x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll); + Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10.0*x); + int ydir = slave?-1:1; + if ( alt ) origin = level.Vec3Offset(origin,-z*2.5+ydir*y*1.5); + else origin = level.Vec3Offset(origin,-z*1.5+ydir*y*2.0); + double a = FRandom[Betamag](0,360), s = FRandom[Betamag](0,alt?invoker.altaccuracy:0.01); + [x2, y2, z2] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll); + Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit(); + FLineTraceData d; + LineTrace(atan2(dir.y,dir.x),10000,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); + if ( d.HitType == TRACE_HitActor ) + { + int dmg = 10; + dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); + double mm = 3000; + if ( FRandom[Betamag](0,1) < 0.2 ) mm *= 5; + UTMainHandler.DoKnockback(d.HitActor,d.HitDir,mm); + if ( d.HitActor.bNOBLOOD ) + { + let p = Spawn("BulletImpact",d.HitLocation); + p.angle = atan2(d.HitDir.y,d.HitDir.x)+180; + p.pitch = asin(d.HitDir.z); + } + else + { + d.HitActor.TraceBleed(dmg,self); + d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg); + } + } + else if ( d.HitType != TRACE_HitNone ) + { + 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("BulletImpact",d.HitLocation+hitnormal*0.01); + p.angle = atan2(hitnormal.y,hitnormal.x); + p.pitch = asin(-hitnormal.z); + if ( d.HitLine ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation); + } + for ( int i=0; i<3; i++ ) + { + let s = Spawn("UTViewSmoke",origin); + if ( alt ) UTViewSmoke(s).ofs = (10,ydir,-3); + else UTViewSmoke(s).ofs = (10,4*ydir,-1); + s.target = self; + s.alpha *= 0.5; + } + origin = level.Vec3Offset(origin,x*5.0+ydir*y*8.0-z*2.0); + let c = Spawn(slave?"BCasing2":"BCasing",origin); + c.vel = x*FRandom[Junk](-1.5,1.5)+y*ydir*FRandom[Junk](2,4)+z*FRandom[Junk](2,3); + } + override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack ) + { + if ( Amount > 1 ) return StringTable.Localize("$O_PROTOMAG2"); + return StringTable.Localize("$O_PROTOMAG"); + } + override void Travelled() + { + Super.Travelled(); + slaveactive = false; + } + override void OwnerDied() + { + Super.OwnerDied(); + slaverefire = 0; + } + override void Tick() + { + Super.Tick(); + if ( sting_protomags && (MaxAmount <= 1) ) MaxAmount = 2; + else if ( !sting_protomags && (MaxAmount > 1) ) MaxAmount = 1; + if ( !Owner || sting_protomags || (Amount <= 1) ) return; + // no dual wielding + if ( Owner.player.ReadyWeapon == self ) + { + // delete the slave overlay + PSprite psp; + for ( psp = Owner.player.psprites; psp; psp = psp.next ) + { + if ( (psp.Caller == self) && ((psp.id == 2) || (psp.id == -9998)) ) psp.Destroy(); + slaveactive = false; + slavedown = false; + } + } + Amount = 1; + } Default { Tag "$T_PROTOMAG"; @@ -17,6 +283,8 @@ Class Betamag : UnrealWeapon Weapon.AmmoGive 20; Weapon.Kickback 320; UTWeapon.DropAmmo 10; + +WEAPON.AMMO_OPTIONAL; + +WEAPON.ALT_AMMO_OPTIONAL; } States { @@ -25,5 +293,258 @@ Class Betamag : UnrealWeapon Stop; AUTP B -1; Stop; + Select: + AUTS A 1 A_Raise(int.max); + Ready: + AUTS A 0 + { + invoker.slavedown = false; + if ( !invoker.slaveactive && (CountInv("Betamag") > 1) ) + player.setpsprite(2,ResolveState("LeftReady")); + } + AUTS ABCDEFGHIJK 2 A_WeaponReady(WRF_NOFIRE); + Idle: + AUTI A 0 A_Overlay(-9999,"Dummy"); + AUTI ABCDEF 20; + AUTI A 0 A_Jump(50,"Twiddle"); + Goto Idle+1; + LeftReady: + 2UTS A 0 + { + A_PlaySound("betamag/select",CHAN_6,!Dampener.Active(self)?1.:.1); + invoker.slaveactive = true; + } + 2UTS ABCDEFGHIJK 2 A_JumpIf(invoker.slavedown,"LeftDeselect"); + LeftIdle: + 2UTI A 0 A_Overlay(-9998,"LeftDummy"); + 2UTI ABCDEF 20; + 2UTI A 0 A_Jump(50,"LeftTwiddle"); + Goto LeftIdle+1; + Twiddle: + AUTT A 0 { invoker.special1 = Random[Betamag](2,3); } + AUTT ABCDEFGHIJKLMNOPQ 3 A_SetTics(invoker.special1); + Goto Idle+1; + LeftTwiddle: + 2UTT A 0 { invoker.special2 = Random[Betamag](2,3); } + 2UTT ABCDEFGHIJKLMNOPQ 3 A_SetTics(invoker.special2); + Goto LeftIdle+1; + Dummy: + TNT1 A 1 + { + A_WeaponReady(WRF_ALLOWRELOAD|WRF_ALLOWZOOM); + if ( !invoker.slaveactive && (CountInv("Betamag") > 1) ) + player.setpsprite(2,ResolveState("LeftReady")); + } + Wait; + LeftDummy: + TNT1 A 1 + { + if ( health <= 0 ) + { + invoker.slaveactive = false; + player.setpsprite(2,ResolveState("LeftDeselect")); + } + else if ( invoker.slavedown ) player.setpsprite(2,ResolveState("LeftDeselect")); + else if ( invoker.slavewhip ) player.setpsprite(2,ResolveState("LeftReload")); + else if ( invoker.slavespin ) player.setpsprite(2,ResolveState("LeftZoom")); + else A_LeftWeaponReady(); + } + Wait; + Fire: + AUTF A 2 + { + A_Overlay(-9999,null); + return A_JumpIfNoAmmo("Reload"); + } + AUTF B 2; + Hold: + AUTF C 2 A_BetamagFire(); + AUTF DE 2; + AUTF F 0 A_PlaySound("betamag/slide",CHAN_ITEM,!Dampener.Active(self)?.3:.03); + AUTF FGHI 2; + AUTF J 0 A_BetamagRefire("Hold"); + AUTF J 2; + AUTI A 0; + Goto Idle; + LeftFire: + #### # 10 A_Overlay(-9998,null); + 2UTI A 0 A_BetamagRefire(1,true); + Goto LeftIdle; + 2UTF AB 1; + LeftHold: + 2UTF C 2 A_BetamagFire(false,true); + 2UTF DE 2; + 2UTF F 0 A_PlaySound("betamag/slide",CHAN_7,!Dampener.Active(self)?.3:.03); + 2UTF FGHI 2; + 2UTF J 0 A_BetamagRefire("LeftHold",true); + 2UTF J 2; + 2UTI A 0; + Goto LeftIdle; + AltFire: + AUTA A 0 + { + invoker.altaccuracy = 0.08; + A_Overlay(-9999,null); + return A_JumpIfNoAmmo("Reload"); + } + AUTA ABCDEFG 2; + AltHold: + AUTA H 2 A_BetamagFire(true); + AUTA I 2; + AUTA J 0 A_PlaySound("betamag/slide",CHAN_ITEM,!Dampener.Active(self)?.3:.03); + AUTA JKLM 2; + AUTA N 0 A_BetamagRefire("AltHold"); + AltRelease: + AUTA NOPQ 2; + AUTI A 2; + Goto Idle; + LeftAltFire: + #### # 6 A_Overlay(-9998,null); + 2UTI A 0 A_BetamagRefire(1,true); + Goto LeftIdle; + 2UTA ABCDEFG 2; + LeftAltHold: + 2UTA H 2 A_BetamagFire(true,true); + 2UTA I 2; + 2UTA J 0 A_PlaySound("betamag/slide",CHAN_7,!Dampener.Active(self)?.3:.03); + 2UTA JKLM 2; + 2UTA N 0 A_BetamagRefire("LeftAltHold",true); + 2UTA NOPQ 2; + 2UTI A 2; + Goto LeftIdle; + Reload: + AUTW A 0 + { + A_Overlay(-9999,null); + invoker.slavewhip = true; + UTMainHandler.DoSwing(self,(FRandom[Betamag](-0.5,-0.4),FRandom[Betamag](0.2,0.3)),4,0,8,SWING_Spring,5); + } + AUTW ABCDE 2; + AUTW F 0 + { + if ( self is 'UTPlayer' ) UTPlayer(self).PlayAttacking3(); + A_PlaySound("betamag/whip",CHAN_ITEM); + UTMainHandler.DoSwing(self,(FRandom[Betamag](-0.3,-0.2),FRandom[Betamag](-0.8,-0.5)),2,0,8,SWING_Spring,2,0.5); + } + AUTW FGHIJ 2; + AUTW K 0 + { + UTMainHandler.DoSwing(self,(FRandom[Betamag](0.2,0.3),FRandom[Betamag](0.8,0.5)),3,0.5,6,SWING_Spring,3,3); + } + AUTW KLM 1; + AUTW N 0 A_BetamagWhip(); + AUTW NOPQR 1; + AUTW STUVWXYZ[\ 2; + Goto Idle; + LeftReload: + #### # 25 + { + invoker.slavewhip = false; + A_Overlay(-9998,null); + } + LeftReloadHold: + 2UTI A 0 + { + if ( !(player.cmd.buttons&BT_RELOAD) ) return ResolveState("LeftIdle"); + invoker.slavewhip = false; + A_Overlay(-9998,null); + UTMainHandler.DoSwing(self,(FRandom[Betamag](0.4,0.5),FRandom[Betamag](0.2,0.3)),4,0,8,SWING_Spring,5); + return ResolveState(null); + } + 2UTW ABCDE 2; + 2UTW F 0 + { + if ( self is 'UTPlayer' ) UTPlayer(self).PlayAttacking3(); + A_PlaySound("betamag/whip",CHAN_7); + UTMainHandler.DoSwing(self,(FRandom[Betamag](0.2,0.3),FRandom[Betamag](-0.8,-0.5)),2,0,8,SWING_Spring,2,0.5); + } + 2UTW FGHIJ 2; + 2UTW K 0 + { + UTMainHandler.DoSwing(self,(FRandom[Betamag](-0.3,-0.2),FRandom[Betamag](0.8,0.5)),3,0.5,6,SWING_Spring,3,3); + } + 2UTW KLM 1; + 2UTW N 0 A_BetamagWhip(); + 2UTW NOPQR 1; + 2UTW STUVWXYZ[\ 2; + 2UTI A 0 A_JumpIf(player.cmd.buttons&BT_RELOAD,"LeftReloadHold"); + Goto LeftIdle; + Zoom: + AUTR A 1 + { + A_Overlay(-9999,null); + invoker.slavespin = true; + } + AUTR BCDEFGHIJKLMN 1; + ZoomLoop: + AUTR OPQRSTUVWX 1; + AUTR Y 0 A_JumpIf(player.cmd.buttons&BT_ZOOM,"ZoomLoop"); + AUTR YZ[\] 1; + AUR2 ABCDEFGHIJK 1; + Goto Idle; + LeftZoom: + 2UTR A 1 + { + A_Overlay(-9998,null); + invoker.slavespin = false; + } + 2UTR BCDEFGHIJKLMN 1; + LeftZoomLoop: + 2UTR OPQRSTUVWX 1; + 2UTR Y 0 A_JumpIf(player.cmd.buttons&BT_ZOOM,"LeftZoomLoop"); + 2UTR YZ[\] 1; + 2UR2 ABCDEFGHIJK 1; + Goto LeftIdle; + Deselect: + AUTI A 1 { invoker.slavedown = true; } + AUTD A 0 A_Overlay(-9999,null); + AUTD A 0 A_JumpIf(invoker.slaveactive,"Deselect"); + AUTD ABCDEFG 1; + AUTD G 1 A_Lower(int.max); + Wait; + LeftDeselect: + 2UTD A 0 + { + A_Overlay(-9998,null); + invoker.slaveactive = false; + } + 2UTD ABCDEFG 1; + Stop; + MuzzleFlash: + AMZ1 # 2 Bright + { + let psp = player.FindPSprite(OverlayID()); + psp.frame = Random[Betamag](0,3); + let l = Spawn("EnforcerLight",pos); + l.target = self; + } + Stop; + AltMuzzleFlash: + AMZ2 # 2 Bright + { + let psp = player.FindPSprite(OverlayID()); + psp.frame = Random[Betamag](0,3); + let l = Spawn("EnforcerLight",pos); + l.target = self; + } + Stop; + LeftMuzzleFlash: + AMZ3 # 2 Bright + { + let psp = player.FindPSprite(OverlayID()); + psp.frame = Random[Betamag](0,3); + let l = Spawn("EnforcerLight",pos); + l.target = self; + } + Stop; + LeftAltMuzzleFlash: + AMZ4 # 2 Bright + { + let psp = player.FindPSprite(OverlayID()); + psp.frame = Random[Betamag](0,3); + let l = Spawn("EnforcerLight",pos); + l.target = self; + } + Stop; } }