extends Control ## Greybox hand HUD: two card slots (bottom center), charge pips above ## them, dilation knob readout (dev instrumentation, not game UI). ## Iconic, not textual — slots are tag-hue blocks, no card text. @onready var _hand: CanvasLayer = get_parent() func _draw() -> void: var slot_w := 24.0 var slot_h := 32.0 var gap := 6.0 var total := slot_w * 2 + gap var x0 := (640.0 - total) / 2.0 var y0 := 320.0 var lvl: int = _hand.card_level() var font_slots := ThemeDB.fallback_font for i in 2: var rect := Rect2(x0 + i * (slot_w + gap), y0, slot_w, slot_h) if i >= _hand.belt.size(): # Belt ran dry: empty slot frame. draw_rect(rect, Color(0.2, 0.22, 0.25, 0.6)) continue var card: Dictionary = _hand.CARD_TYPES[_hand.belt[i]] var affordable: bool = _hand.charges >= int(card.cost) var hue: Color = card.hue if not affordable: hue = Color(hue.r, hue.g, hue.b, 0.25) elif not _hand.hand_open: hue = Color(hue.r, hue.g, hue.b, 0.6) draw_rect(rect, hue) draw_string(font_slots, Vector2(rect.position.x + 8.0, rect.position.y + 20.0), card.glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 12, Color(0.1, 0.1, 0.12, 0.9)) if _hand.hand_open: draw_rect(rect.grow(1.0), Color(1, 1, 1, 0.9 if affordable else 0.3), false, 1.0) # Card level: notches under the slot. for n in lvl: draw_rect(Rect2(rect.position.x + n * 8.0, rect.end.y + 3.0, 5.0, 3.0), Color(0.95, 0.8, 0.35)) # Belt depth: upcoming cards as thin ticks left of the slots, in # card hue — the ammo readout. for i in range(2, _hand.belt.size()): var card: Dictionary = _hand.CARD_TYPES[_hand.belt[i]] draw_rect(Rect2(x0 - 12.0 - (i - 2) * 6.0, y0 + 8.0, 4.0, 16.0), Color(card.hue.r, card.hue.g, card.hue.b, 0.7)) # Salvage counter: scrap diamond + running total, right of the slots. var dx := x0 + total + 16.0 var dy := y0 + 14.0 var dia := PackedVector2Array([Vector2(dx, dy - 5), Vector2(dx + 4, dy), Vector2(dx, dy + 5), Vector2(dx - 4, dy)]) draw_colored_polygon(dia, Color(0.95, 0.8, 0.35)) draw_string(ThemeDB.fallback_font, Vector2(dx + 8.0, dy + 4.0), str(_hand.salvage_total), HORIZONTAL_ALIGNMENT_LEFT, -1, 10, Color(0.85, 0.85, 0.9)) var pip := 5.0 var pips_w: float = float(_hand.max_charges) * (pip + 3.0) - 3.0 var px0: float = (640.0 - pips_w) / 2.0 for i in int(_hand.max_charges): var filled: bool = i < int(_hand.charges) var c := Color(0.9, 0.9, 0.95) if filled else Color(0.9, 0.9, 0.95, 0.18) draw_rect(Rect2(px0 + i * (pip + 3.0), y0 - 10.0, pip, pip), c) if _hand.meter_mode: # Freeze meter: fill color names the band you'd open into. var bw := 84.0 var bh := 4.0 var bx := (640.0 - bw) / 2.0 var by := y0 - 20.0 draw_rect(Rect2(bx, by, bw, bh), Color(0.9, 0.9, 0.95, 0.12)) var f: float = _hand.frac() var col := Color(0.85, 0.95, 1.0) if f < _hand.band_unavailable: col = Color(0.8, 0.3, 0.25) elif f < _hand.band_realtime: col = Color(0.55, 0.57, 0.6) elif f < _hand.band_thaw: col = Color(0.55, 0.75, 0.95) draw_rect(Rect2(bx, by, bw * f, bh), col) for b: float in [_hand.band_unavailable, _hand.band_realtime, _hand.band_thaw]: var tx := bx + bw * b draw_line(Vector2(tx, by - 1), Vector2(tx, by + bh + 1), Color(0.1, 0.1, 0.12, 0.9), 1.0) var font := ThemeDB.fallback_font var label: String = "frz %.1f/%.1fs" % [_hand.meter, _hand.meter_max] if _hand.meter_mode else "dt x%.2f" % _hand.dilation_scale draw_string(font, Vector2(560, 352), label, HORIZONTAL_ALIGNMENT_LEFT, -1, 8, Color(0.6, 0.65, 0.7, 0.7))