Files

134 lines
6.4 KiB
C#
Raw Permalink Normal View History

using UnityEngine;
using UnityEngine.UIElements;
namespace Ironspore
{
// Field-only instruments. Weapon state and navigation targets belong to the simulation.
public sealed class CombatInstruments
{
readonly VisualElement field, map;
readonly GameSession game;
readonly Label primary, rounds, reload, secondary, cargo;
readonly string reloadHint;
float nextMapUpdate;
int displayedRounds = -1;
public CombatInstruments(VisualElement field, VisualElement vitals, GameSession game)
{
this.field = field;
this.game = game;
var nav = Panel("combat-nav");
Caption(nav, GameLocalization.Text("ui.combat.nav") + " N ↑", "combat-kicker");
map = new VisualElement();
map.AddToClassList("combat-map");
nav.Add(map);
map.generateVisualContent += DrawMap;
Caption(nav, GameLocalization.Text("ui.combat.legend"), "combat-small");
var weapon = Panel("combat-weapon");
primary = Caption(weapon, "", "combat-primary");
Caption(weapon, GameLocalization.Text("ui.combat.ammo"), "combat-kicker");
var row = new VisualElement();
row.AddToClassList("combat-rounds-row");
weapon.Add(row);
rounds = Caption(row, "", "combat-rounds");
reload = Caption(row, "", "combat-small");
secondary = Caption(weapon, "", "combat-secondary");
cargo = Caption(vitals, "", "combat-cargo");
reloadHint = GameLocalization.Text("ui.combat.reload", game.Settings.Bindings.Display("Reload"));
}
VisualElement Panel(string style)
{
var panel = new VisualElement();
panel.AddToClassList("combat-panel");
panel.AddToClassList(style);
field.Add(panel);
return panel;
}
static Label Caption(VisualElement parent, string text, string style)
{
var label = new Label(text);
label.AddToClassList(style);
parent.Add(label);
return label;
}
public void Refresh()
{
var pilot = game.Pilot;
field.EnableInClassList("cockpit-hud", pilot.FirstPerson);
bool redraw = Time.unscaledTime >= nextMapUpdate;
if (!redraw && pilot.Rounds == displayedRounds) return;
displayedRounds = pilot.Rounds;
primary.text = pilot.Primary.LocalizedName;
rounds.text = pilot.Rounds.ToString();
rounds.EnableInClassList("ammo-low", pilot.Rounds <= pilot.Primary.magazineSize / 4);
reload.text = pilot.ReloadRemaining > 0 ? GameLocalization.Text("ui.combat.loading", pilot.ReloadRemaining) : reloadHint;
var state = pilot.SecondaryCooldown > 0 ? GameLocalization.Text("ui.combat.charging", pilot.SecondaryCooldown) :
GameLocalization.Text(pilot.Energy < 15 ? "ui.combat.lowEnergy" : "ui.combat.ready");
secondary.text = game.Part(1, game.Run.equipment[1]).LocalizedName + " · " + state;
cargo.text = GameLocalization.Text("ui.combat.cargo", game.Run.cargo.Count);
if (redraw)
{
map.MarkDirtyRepaint();
nextMapUpdate = Time.unscaledTime + .075f;
}
}
void DrawMap(MeshGenerationContext context)
{
var pilot = game.Pilot;
if (!pilot || !game.InField) return;
var painter = context.painter2D;
var rect = map.contentRect;
// Keep north up and use one scale on both axes. Include the pilot past the yard edges.
var position = pilot.transform.position;
var scale = Mathf.Min(rect.width / Mathf.Max(90, Mathf.Abs(position.x) * 2 + 8),
rect.height / Mathf.Max(100, Mathf.Abs(position.z - 8) * 2 + 8));
Vector2 Project(float x, float z) => rect.center + new Vector2(x, 8 - z) * scale;
void Line(Vector2 a, Vector2 b)
{
painter.BeginPath(); painter.MoveTo(a); painter.LineTo(b); painter.Stroke();
}
painter.lineWidth = 1;
painter.strokeColor = new Color(.15f, .28f, .30f);
for (int x = -30; x <= 30; x += 10) Line(Project(x, -40), Project(x, 56));
for (int z = -40; z <= 50; z += 10) Line(Project(-35, z), Project(35, z));
painter.lineWidth = 2;
painter.strokeColor = new Color(.33f, .49f, .5f);
Line(Project(-35, -38), Project(-35, 58));
Line(Project(35, -38), Project(35, 58));
painter.fillColor = painter.strokeColor;
for (int i = 0; i < game.World.Cover.Count; i++)
{
var box = game.World.Cover[i];
painter.BeginPath(); painter.MoveTo(Project(box.xMin, box.yMin));
painter.LineTo(Project(box.xMax, box.yMin)); painter.LineTo(Project(box.xMax, box.yMax));
painter.LineTo(Project(box.xMin, box.yMax)); painter.ClosePath(); painter.Fill();
}
var target = game.World.NavigationTarget;
if (target)
{
var pos = Project(target.position.x, target.position.z);
painter.strokeColor = new Color(.45f, .84f, 1);
painter.BeginPath(); painter.MoveTo(pos + Vector2.up * 6);
painter.LineTo(pos + Vector2.right * 6); painter.LineTo(pos + Vector2.down * 6);
painter.LineTo(pos + Vector2.left * 6); painter.ClosePath(); painter.Stroke();
}
var pad = game.World.ExtractionPosition;
painter.strokeColor = game.World.TransportReady ? Color.green : new Color(1, .72f, .36f);
painter.BeginPath(); painter.Arc(Project(pad.x, pad.z), 6, 0, 360); painter.Stroke();
var origin = Project(position.x, position.z);
var radians = pilot.Heading * Mathf.Deg2Rad;
var forward = new Vector2(Mathf.Sin(radians), -Mathf.Cos(radians));
var right = new Vector2(-forward.y, forward.x);
painter.fillColor = new Color(.43f, 1, .80f);
painter.BeginPath(); painter.MoveTo(origin + forward * 9);
painter.LineTo(origin - forward * 6 + right * 5); painter.LineTo(origin - forward * 6 - right * 5);
painter.ClosePath(); painter.Fill();
}
}
}