diff --git a/src/Items/Weapon.cs b/src/Items/Weapon.cs index 7986f4f..f8f1682 100644 --- a/src/Items/Weapon.cs +++ b/src/Items/Weapon.cs @@ -2,9 +2,8 @@ using System; using Godot; // TODO: "Click" sound when attempting to fire when not ready, or empty. -// TODO: "Reload" sound when reloading. // TODO: "Single reload" for revolver & shotgun. -// TODO: Add outline around sprites. +// TODO: Add outline around weapon sprites. public class Weapon : Sprite { @@ -58,8 +57,7 @@ public class Weapon : Sprite if (!(Player is LocalPlayer)) return; if (ev.IsActionPressed("interact_primary")) { HoldingTrigger = TimeSpan.Zero; OnTriggerPressed(); } - if (ev.IsActionPressed("interact_reload") && (Rounds < Capacity) && (_reloading == null)) - { _reloading = ReloadTime; } + if (ev.IsActionPressed("interact_reload")) Reload(); } protected virtual void OnTriggerPressed() => Fire(); @@ -82,9 +80,7 @@ public class Weapon : Sprite Rounds = Capacity; _reloading = null; } - } else if (Rounds <= 0) - // Automatically reload when out of rounds. - _reloading = ReloadTime; + } if (_fireDelay > 0) { _fireDelay -= delta; @@ -96,6 +92,9 @@ public class Weapon : Sprite } if (Player is LocalPlayer) { + // Automatically reload when out of rounds. + if (Rounds <= 0) Reload(); + if (HoldingTrigger != null) { if (!Input.IsActionPressed("interact_primary")) { HoldingTrigger = null; @@ -126,7 +125,7 @@ public class Weapon : Sprite AimDirection = Cursor.Position.AngleToPoint(Player.Position) - angleC; // FIXME: Angle calculation when cursor is too close to player. - RpcId(1, nameof(SendAimAngle), AimDirection); + RpcUnreliableId(1, nameof(SendAimAngle), AimDirection); Update(); } } else { @@ -140,50 +139,6 @@ public class Weapon : Sprite Rotation = AimDirection - _currentRecoil * ((Scale.y > 0) ? 1 : -1); } - public override void _Draw() - { - if (!(Player is LocalPlayer)) return; - // Draws an "aiming cone" to show where bullets might travel. - - var tip = TipOffset + new Vector2(4, 0); - var angle = Mathf.Sin((Mathf.Deg2Rad(Spread) + _currentSpreadInc) / 2); - var color = Colors.Black; - - var points = new Vector2[8]; - var colors = new Color[8]; - colors[0] = colors[7] = new Color(color, 0.0F); - points[0] = points[7] = tip; - colors[1] = colors[6] = new Color(color, 0.15F); - points[1] = tip + new Vector2(1, angle) * 64; - points[6] = tip + new Vector2(1, -angle) * 64; - colors[2] = colors[5] = new Color(color, 0.15F); - points[2] = tip + new Vector2(1, angle) * EffectiveRange; - points[5] = tip + new Vector2(1, -angle) * EffectiveRange; - colors[3] = colors[4] = new Color(color, 0.0F); - points[3] = tip + new Vector2(1, angle) * MaximumRange; - points[4] = tip + new Vector2(1, -angle) * MaximumRange; - - var st = new SurfaceTool(); - st.Begin(Mesh.PrimitiveType.TriangleStrip); - st.AddColor(colors[0]); - st.AddVertex(To3(points[0])); - st.AddColor(colors[1]); - st.AddVertex(To3(points[1])); - st.AddVertex(To3(points[6])); - st.AddColor(colors[2]); - st.AddVertex(To3(points[2])); - st.AddVertex(To3(points[5])); - st.AddColor(colors[3]); - st.AddVertex(To3(points[3])); - st.AddVertex(To3(points[4])); - st.Index(); - - DrawMesh(st.Commit(), null); - DrawPolylineColors(points, colors, antialiased: true); - } - private static Vector3 To3(Vector2 vec) - => new Vector3(vec.x, vec.y, 0); - [Remote] private void SendAimAngle(float value) @@ -197,26 +152,15 @@ public class Weapon : Sprite AimDirection = value; } + private void Fire() { var seed = unchecked((int)GD.Randi()); if (!FireInternal(AimDirection, Scale.y > 0, seed)) return; - RpcId(1, nameof(Fire), AimDirection, Scale.y > 0, seed); + RpcId(1, nameof(SendFire), AimDirection, Scale.y > 0, seed); ((LocalPlayer)Player).Velocity -= Mathf.Polar2Cartesian(Knockback, Rotation); } - [Remote] - private void Fire(float aimDirection, bool toRight, int seed) - { - if (this.GetGame() is Server) { - if (Player.NetworkID != GetTree().GetRpcSenderId()) return; - // TODO: Verify input. - if (FireInternal(aimDirection, toRight, seed)) - Rpc(nameof(Fire), aimDirection, toRight, seed); - } else if (!(Player is LocalPlayer)) - FireInternal(aimDirection, toRight, seed); - } - protected virtual bool FireInternal(float aimDirection, bool toRight, int seed) { if ((_reloading != null) || (Rounds <= 0) || (_fireDelay > 0)) return false; @@ -246,4 +190,83 @@ public class Weapon : Sprite } return true; } + + [Remote] + private void SendFire(float aimDirection, bool toRight, int seed) + { + if (this.GetGame() is Server) { + if (Player.NetworkID != GetTree().GetRpcSenderId()) return; + // TODO: Verify input. + if (FireInternal(aimDirection, toRight, seed)) + Rpc(nameof(SendFire), aimDirection, toRight, seed); + } else if (!(Player is LocalPlayer)) + FireInternal(aimDirection, toRight, seed); + } + + + private void Reload() + { if (ReloadInternal()) RpcId(1, nameof(SendReload)); } + + private bool ReloadInternal() + { + if ((Rounds >= Capacity) || (_reloading != null)) return false; + // TODO: Play reload sound. + _reloading = ReloadTime; + return true; + } + + [Remote] + private void SendReload() + { + if (this.GetGame() is Server) { + if (Player.NetworkID != GetTree().GetRpcSenderId()) return; + if (ReloadInternal()) Rpc(nameof(SendReload)); + } else if (!(Player is LocalPlayer)) + ReloadInternal(); + } + + + public override void _Draw() + { + if (!(Player is LocalPlayer)) return; + // Draws an "aiming cone" to show where bullets might travel. + + var tip = TipOffset + new Vector2(4, 0); + var angle = Mathf.Sin((Mathf.Deg2Rad(Spread) + _currentSpreadInc) / 2); + var color = Colors.Black; + + var points = new Vector2[8]; + var colors = new Color[8]; + colors[0] = colors[7] = new Color(color, 0.0F); + points[0] = points[7] = tip; + colors[1] = colors[6] = new Color(color, 0.15F); + points[1] = tip + new Vector2(1, angle) * 64; + points[6] = tip + new Vector2(1, -angle) * 64; + colors[2] = colors[5] = new Color(color, 0.15F); + points[2] = tip + new Vector2(1, angle) * EffectiveRange; + points[5] = tip + new Vector2(1, -angle) * EffectiveRange; + colors[3] = colors[4] = new Color(color, 0.0F); + points[3] = tip + new Vector2(1, angle) * MaximumRange; + points[4] = tip + new Vector2(1, -angle) * MaximumRange; + + var st = new SurfaceTool(); + st.Begin(Mesh.PrimitiveType.TriangleStrip); + st.AddColor(colors[0]); + st.AddVertex(To3(points[0])); + st.AddColor(colors[1]); + st.AddVertex(To3(points[1])); + st.AddVertex(To3(points[6])); + st.AddColor(colors[2]); + st.AddVertex(To3(points[2])); + st.AddVertex(To3(points[5])); + st.AddColor(colors[3]); + st.AddVertex(To3(points[3])); + st.AddVertex(To3(points[4])); + st.Index(); + + DrawMesh(st.Commit(), null); + DrawPolylineColors(points, colors, antialiased: true); + } + private static Vector3 To3(Vector2 vec) + => new Vector3(vec.x, vec.y, 0); }