Skip to content

Commit 735b57f

Browse files
committed
Port the SDK stunstick
1 parent 8df8e94 commit 735b57f

1 file changed

Lines changed: 212 additions & 2 deletions

File tree

‎Game.Shared/GarrysMod/WeaponStunStick.cs‎

Lines changed: 212 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
#if (CLIENT_DLL || GAME_DLL) && GMOD_DLL
2+
#if GAME_DLL
3+
using Game.Server;
4+
#endif
5+
using Source;
26
using Source.Common;
7+
using Source.Common.Mathematics;
8+
9+
using System.Numerics;
310
namespace Game.Shared.GarrysMod;
411
using FIELD = Source.FIELD<WeaponStunStick>;
512

613
[LinkEntityToClass("weapon_stunstick")]
714
[PrecacheWeaponRegister("weapon_stunstick")]
815
[NetworkName("CWeaponStunStick")]
9-
public class WeaponStunStick : BaseHL2MPBludgeonWeapon
16+
public partial class WeaponStunStick : BaseHL2MPBludgeonWeapon
1017
{
1118
public static readonly
1219
#if CLIENT_DLL
@@ -28,7 +35,210 @@ public static readonly
2835
public static readonly new ServerClass ServerClass = new ServerClass(DT_WeaponStunStick);
2936
#endif
3037
[NetworkName("m_bActive")]
38+
#if CLIENT_DLL
3139
public bool Active;
32-
public override float GetFireRate() => 0.2f;
40+
#else
41+
[NetworkVar] public partial bool Active { get; set; }
42+
#endif
43+
44+
public const float STUNSTICK_RANGE = 75.0f;
45+
public const float STUNSTICK_REFIRE = 0.8f;
46+
public const string STUNSTICK_BEAM_MATERIAL = "sprites/lgtning.vmt";
47+
48+
#if !CLIENT_DLL
49+
static readonly ActTable[] acttable = [
50+
new() { BaseAct = Activity.ACT_RANGE_ATTACK1, WeaponAct = Activity.ACT_RANGE_ATTACK_SLAM, Required = true },
51+
new() { BaseAct = Activity.ACT_HL2MP_IDLE, WeaponAct = Activity.ACT_HL2MP_IDLE_MELEE, Required = false },
52+
new() { BaseAct = Activity.ACT_HL2MP_RUN, WeaponAct = Activity.ACT_HL2MP_RUN_MELEE, Required = false },
53+
new() { BaseAct = Activity.ACT_HL2MP_IDLE_CROUCH, WeaponAct = Activity.ACT_HL2MP_IDLE_CROUCH_MELEE, Required = false },
54+
new() { BaseAct = Activity.ACT_HL2MP_WALK_CROUCH, WeaponAct = Activity.ACT_HL2MP_WALK_CROUCH_MELEE, Required = false },
55+
new() { BaseAct = Activity.ACT_HL2MP_GESTURE_RANGE_ATTACK, WeaponAct = Activity.ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, Required = false },
56+
new() { BaseAct = Activity.ACT_HL2MP_GESTURE_RELOAD, WeaponAct = Activity.ACT_HL2MP_GESTURE_RELOAD_MELEE, Required = false },
57+
new() { BaseAct = Activity.ACT_HL2MP_JUMP, WeaponAct = Activity.ACT_HL2MP_JUMP_MELEE, Required = false },
58+
];
59+
60+
public override ReadOnlySpan<ActTable> ActivityList() => acttable;
61+
#endif
62+
63+
public WeaponStunStick() {
64+
Active = false;
65+
}
66+
67+
public override void Spawn() {
68+
Precache();
69+
70+
base.Spawn();
71+
AddSolidFlags(SolidFlags.NotStandable);
72+
}
73+
74+
public override void Precache() {
75+
base.Precache();
76+
77+
PrecacheScriptSound("Weapon_StunStick.Activate");
78+
PrecacheScriptSound("Weapon_StunStick.Deactivate");
79+
80+
PrecacheModel(STUNSTICK_BEAM_MATERIAL);
81+
PrecacheModel("sprites/light_glow02_add.vmt");
82+
PrecacheModel("effects/blueflare1.vmt");
83+
PrecacheModel("sprites/light_glow02_add_noz.vmt");
84+
}
85+
86+
public override float GetRange() => STUNSTICK_RANGE;
87+
public override float GetFireRate() => STUNSTICK_REFIRE;
88+
89+
public override float GetDamageForActivity(Activity hitActivity) => 40.0f;
90+
91+
public override bool PlayFleshyHittySoundOnHit() => true;
92+
93+
public override void SecondaryAttack() { }
94+
95+
#if !CLIENT_DLL
96+
public override SCOND_t WeaponMeleeAttack1Condition(float dot, float dist) {
97+
AI_BaseNPC npc = GetOwner()!.MyNPCPointer()!;
98+
BaseEntity? enemy = npc.GetEnemy();
99+
if (enemy == null)
100+
return SCOND_t.COND_NONE;
101+
102+
enemy.GetVelocity(out Vector3 velocity, out _);
103+
104+
float dt = WeaponCrowbar.sk_crowbar_lead_time.GetFloat();
105+
dt += random.RandomFloat(-0.3f, 0.2f);
106+
if (dt < 0.0f)
107+
dt = 0.0f;
108+
109+
MathLib.VectorMA(enemy.WorldSpaceCenter(), dt, velocity, out Vector3 extrapolatedPos);
110+
111+
Vector3 delta = extrapolatedPos - npc.WorldSpaceCenter();
112+
113+
if (MathF.Abs(delta.Z) > 70)
114+
return SCOND_t.COND_TOO_FAR_TO_ATTACK;
115+
116+
Vector3 forward = npc.BodyDirection2D();
117+
delta.Z = 0.0f;
118+
float extrapolatedDot = MathLib.DotProduct2D(delta.AsVector2D(), forward.AsVector2D());
119+
if ((dot < 0.7) && (extrapolatedDot < 0.7))
120+
return SCOND_t.COND_NOT_FACING_ATTACK;
121+
122+
float extrapolatedDist = MathLib.Vector2DLength(delta.AsVector2D());
123+
124+
if (enemy.IsPlayer()) {
125+
Vector3 projectEnemy = enemy.GetAbsOrigin() + (enemy.GetAbsVelocity() * 0.35f);
126+
Vector3 projectMe = GetAbsOrigin();
127+
128+
if (MathLib.Vector2DLength((projectMe - projectEnemy).AsVector2D()) <= 48.0f)
129+
return SCOND_t.COND_CAN_MELEE_ATTACK1;
130+
}
131+
132+
float targetDist = 48.0f;
133+
if ((dist > targetDist) && (extrapolatedDist > targetDist))
134+
return SCOND_t.COND_TOO_FAR_TO_ATTACK;
135+
136+
return SCOND_t.COND_CAN_MELEE_ATTACK1;
137+
}
138+
139+
public override void Operator_HandleAnimEvent(ref AnimEvent animEvent, BaseCombatCharacter op) {
140+
switch (animEvent.Event) {
141+
case EVENT_WEAPON_MELEE_HIT: {
142+
MathLib.AngleVectors(GetAbsAngles(), out Vector3 direction);
143+
144+
BaseEntity? enemy = op.MyNPCPointer()?.GetEnemy();
145+
if (enemy != null) {
146+
Vector3 delta = enemy.WorldSpaceCenter() - op.Weapon_ShootPosition();
147+
MathLib.VectorNormalize(ref delta);
148+
149+
Vector2 delta2D = delta.AsVector2D();
150+
float length2D = delta2D.Length();
151+
if (length2D != 0)
152+
delta2D /= length2D;
153+
if (MathLib.DotProduct2D(delta2D, direction.AsVector2D()) > 0.8f)
154+
direction = delta;
155+
}
156+
157+
MathLib.VectorMA(op.Weapon_ShootPosition(), 32, direction, out Vector3 end);
158+
BaseEntity? hurt = op.CheckTraceHullAttack(op.Weapon_ShootPosition(), end,
159+
new(-16, -16, -40), new(16, 16, 16), GetDamageForActivity(GetActivity()), DamageType.Club, 0.5f, false);
160+
161+
if (hurt != null) {
162+
WeaponSound(Shared.WeaponSound.MeleeHit);
163+
164+
BasePlayer? player = ToBasePlayer(hurt);
165+
166+
if (player != null && (player.GetFlags() & EntityFlags.GodMode) == 0) {
167+
float yawKick = random.RandomFloat(-48, -24);
168+
169+
player.ViewPunch(new QAngle(-16, yawKick, 2));
170+
171+
Vector3 dir = hurt.GetAbsOrigin() - GetAbsOrigin();
172+
173+
if (player.GetGroundEntity() == op) {
174+
dir = direction;
175+
dir.Z = 0;
176+
}
177+
178+
MathLib.VectorNormalize(ref dir);
179+
180+
dir *= 500.0f;
181+
182+
if ((player.GetFlags() & EntityFlags.OnGround) == 0)
183+
dir.Z = 0.0f;
184+
185+
hurt.ApplyAbsVelocityImpulse(dir);
186+
187+
Util.ScreenFade(player, new(128, 0, 0, 128), 0.5f, 0.1f, FadeFlags.In);
188+
189+
player.ForceDropOfCarriedPhysObjects(null);
190+
}
191+
}
192+
else
193+
WeaponSound(Shared.WeaponSound.MeleeMiss);
194+
}
195+
break;
196+
default:
197+
base.Operator_HandleAnimEvent(ref animEvent, op);
198+
break;
199+
}
200+
}
201+
#endif
202+
203+
public void SetStunState(bool state) {
204+
Active = state;
205+
206+
if (Active) {
207+
#if !CLIENT_DLL
208+
GetAttachment(1, out Vector3 attachment, out QAngle _);
209+
g_pEffects.Sparks(attachment);
210+
#endif
211+
212+
EmitSound("Weapon_StunStick.Activate");
213+
}
214+
else
215+
EmitSound("Weapon_StunStick.Deactivate");
216+
}
217+
218+
public bool GetStunState() => Active;
219+
220+
public override bool Deploy() {
221+
SetStunState(true);
222+
223+
return base.Deploy();
224+
}
225+
226+
public override bool Holster(BaseCombatWeapon? switchingTo = null) {
227+
if (base.Holster(switchingTo) == false)
228+
return false;
229+
230+
SetStunState(false);
231+
SetWeaponVisible(false);
232+
233+
return true;
234+
}
235+
236+
public override void Drop(in Vector3 velocity) {
237+
SetStunState(false);
238+
239+
#if !CLIENT_DLL
240+
Util.Remove(this);
241+
#endif
242+
}
33243
}
34244
#endif

0 commit comments

Comments
 (0)