|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|