edc40f9008
- Touch controls: direct InputEventScreenTouch in shop_ui (bypass relay) - ItemDB: static preload list instead of DirAccess scan (export fix) - All 18 items with EN localisation (name_en, desc_en, category_en) - Ship playstyles: NOVA-1 shield, INFERNO ram, AURORA agile/tank - Quasar: SMBH visual, jet boost, merge, push, BH-eating - Atlas & UI text updated EN+DE Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
168 lines
6.6 KiB
GDScript
168 lines
6.6 KiB
GDScript
extends Node2D
|
||
|
||
var W: float = 960.0
|
||
var H: float = 600.0
|
||
|
||
# Cockpit palette
|
||
const COL_BG := Color(0.0, 0.04, 0.02, 0.90)
|
||
const COL_PRIMARY := Color(0.0, 1.0, 0.533, 1.0) # phosphor green
|
||
const COL_ACCENT := Color(0.27, 1.0, 0.8, 1.0)
|
||
const COL_DIM := Color(0.0, 0.27, 0.13, 0.6) # lines / brackets only
|
||
const COL_TEXT := Color(0.3, 0.68, 0.46, 0.88) # readable secondary text
|
||
const COL_P2 := Color(0.27, 1.0, 0.67, 1.0)
|
||
const COL_OVERLAY := Color(0.0, 0.0, 0.04, 0.78)
|
||
|
||
var is_p2_mode: bool = false
|
||
var selected: int = 0
|
||
var ships: Array = []
|
||
var blink_phase: float = 0.0
|
||
var enter_blink: bool = true
|
||
var enter_timer: float = 0.0
|
||
|
||
func start_select(p2_mode: bool, start_sel: int, ship_data: Array) -> void:
|
||
is_p2_mode = p2_mode
|
||
selected = start_sel
|
||
ships = ship_data
|
||
visible = true
|
||
blink_phase = 0.0
|
||
|
||
func set_selection(idx: int) -> void:
|
||
selected = idx
|
||
queue_redraw()
|
||
|
||
func _process(delta: float) -> void:
|
||
blink_phase += delta
|
||
enter_timer += delta
|
||
if enter_timer >= 0.5:
|
||
enter_timer = 0.0
|
||
enter_blink = not enter_blink
|
||
queue_redraw()
|
||
|
||
func _draw() -> void:
|
||
var vs: Vector2 = get_viewport_rect().size
|
||
W = vs.x; H = vs.y
|
||
# Background overlay so live simulation shows through
|
||
draw_rect(get_viewport_rect(), COL_OVERLAY)
|
||
|
||
# ── Header bar ───────────────────────────────────────────────────────────
|
||
draw_rect(Rect2(0, 0, W, 52.0), Color(0.0, 0.04, 0.02, 0.92))
|
||
draw_line(Vector2(0, 52), Vector2(W, 52), COL_DIM, 1.0)
|
||
|
||
var header_col := COL_PRIMARY if not is_p2_mode else COL_P2
|
||
_draw_text_centered(Tr.t("select_header"), W * 0.5, 14.0, 10, COL_TEXT)
|
||
var sub := Tr.t("select_pilot1") if not is_p2_mode else Tr.t("select_pilot2")
|
||
_draw_text_centered(sub, W * 0.5, 30.0, 13, header_col)
|
||
|
||
# Outer corner brackets
|
||
_draw_corner_brackets(8.0, 8.0, W - 8.0, H - 8.0, COL_DIM, 16.0)
|
||
|
||
# ── Ship boxes ───────────────────────────────────────────────────────────
|
||
# 2×2 Grid Layout (supports 4 ships, falls back for 3)
|
||
var n := ships.size()
|
||
var cols: int = 2 if n >= 4 else min(n, 3)
|
||
var box_w := 220.0; var box_h := 180.0
|
||
if cols == 3:
|
||
box_w = 210.0; box_h = 220.0
|
||
var row_h: float = box_h + 16.0
|
||
var col_space: float = (W - box_w * cols) / float(cols + 1)
|
||
var grid_start_y: float = 72.0
|
||
for i in n:
|
||
var col_i: int = i % cols
|
||
var row_i: int = int(i / cols)
|
||
var bx: float = col_space + col_i * (box_w + col_space)
|
||
var by: float = grid_start_y + row_i * row_h
|
||
var is_sel := i == selected
|
||
var pulse := 0.5 + 0.5 * sin(blink_phase * 3.0)
|
||
|
||
# Box background
|
||
draw_rect(Rect2(bx, by, box_w, box_h), Color(0.0, 0.04, 0.02, 0.72))
|
||
|
||
# Corner L-brackets instead of full border
|
||
var bracket_col: Color
|
||
if is_sel:
|
||
bracket_col = Color(COL_ACCENT.r, COL_ACCENT.g, COL_ACCENT.b, 0.6 + 0.4 * pulse)
|
||
else:
|
||
bracket_col = COL_DIM
|
||
_draw_corner_brackets(bx, by, bx + box_w, by + box_h, bracket_col, 16.0)
|
||
|
||
# Ship preview
|
||
var cx := bx + box_w * 0.5
|
||
var cy := by + box_h * 0.42
|
||
var preview_heading := blink_phase * 0.6 if is_sel else -PI * 0.5
|
||
_draw_ship_preview(cx, cy, preview_heading, ships[i])
|
||
|
||
# Ship name
|
||
var name_col := COL_ACCENT if is_sel else COL_TEXT
|
||
_draw_text_centered(ships[i]["name"], cx, by + box_h - 42.0, 12, name_col)
|
||
|
||
# Ship identifier or boost hint
|
||
var sub_str: String
|
||
match ships[i]["id"]:
|
||
"classic": sub_str = "1 SHIELD · BALANCED"
|
||
"inferno": sub_str = "SPEED+ · RAM DAMAGE"
|
||
"aurora": sub_str = "2 SHIELDS · BH RESIST"
|
||
"titan": sub_str = "[SHIFT] BOOST"
|
||
_: sub_str = ships[i]["id"].to_upper()
|
||
_draw_text_centered(sub_str, cx, by + box_h - 24.0, 8,
|
||
Color(COL_TEXT.r, COL_TEXT.g, COL_TEXT.b, 0.85))
|
||
|
||
# ── Footer ───────────────────────────────────────────────────────────────
|
||
draw_rect(Rect2(0, H - 48.0, W, 48.0), Color(0.0, 0.04, 0.02, 0.92))
|
||
draw_line(Vector2(0, H - 48.0), Vector2(W, H - 48.0), COL_DIM, 1.0)
|
||
|
||
_draw_text_centered(Tr.hint("select_choose"), W * 0.5, H - 44.0, 9, COL_TEXT)
|
||
|
||
if not is_p2_mode:
|
||
if enter_blink:
|
||
_draw_text_centered(Tr.hint("select_confirm"), W * 0.5, H - 26.0, 11, COL_PRIMARY)
|
||
else:
|
||
_draw_text_centered(Tr.hint("select_join"), W * 0.3, H - 26.0, 10,
|
||
COL_P2 if enter_blink else COL_DIM)
|
||
_draw_text_centered(Tr.hint("select_solo"), W * 0.7, H - 26.0, 10,
|
||
COL_PRIMARY if enter_blink else COL_DIM)
|
||
|
||
# ── Drawing helpers ───────────────────────────────────────────────────────────
|
||
|
||
func _draw_corner_brackets(x1: float, y1: float, x2: float, y2: float,
|
||
col: Color, arm: float) -> void:
|
||
# Top-left
|
||
draw_line(Vector2(x1, y1), Vector2(x1 + arm, y1), col, 1.5)
|
||
draw_line(Vector2(x1, y1), Vector2(x1, y1 + arm), col, 1.5)
|
||
# Top-right
|
||
draw_line(Vector2(x2, y1), Vector2(x2 - arm, y1), col, 1.5)
|
||
draw_line(Vector2(x2, y1), Vector2(x2, y1 + arm), col, 1.5)
|
||
# Bottom-left
|
||
draw_line(Vector2(x1, y2), Vector2(x1 + arm, y2), col, 1.5)
|
||
draw_line(Vector2(x1, y2), Vector2(x1, y2 - arm), col, 1.5)
|
||
# Bottom-right
|
||
draw_line(Vector2(x2, y2), Vector2(x2 - arm, y2), col, 1.5)
|
||
draw_line(Vector2(x2, y2), Vector2(x2, y2 - arm), col, 1.5)
|
||
|
||
func _draw_ship_preview(cx: float, cy: float, heading: float, ship: Dictionary) -> void:
|
||
var cos_h := cos(heading); var sin_h := sin(heading)
|
||
var preview_scale := 5.5
|
||
var hull_pixels := [
|
||
[3, 0, "nose"], [2, -1, "mid"], [2, 1, "mid"],
|
||
[1, 0, "dim"], [0, -2, "accent"],[0, 2, "accent"],
|
||
[0, 0, "bright"],[-1,-1, "dim"], [-1, 1, "dim"],
|
||
[-2,-2, "shadow"],[-2, 2, "shadow"],[-2, 0, "edge"],
|
||
]
|
||
for px_data in hull_pixels:
|
||
var lx: float = px_data[0] * preview_scale
|
||
var ly: float = px_data[1] * preview_scale
|
||
var col: Color = ship.get(px_data[2], Color.WHITE)
|
||
var rx := cx + lx * cos_h - ly * sin_h
|
||
var ry := cy + lx * sin_h + ly * cos_h
|
||
draw_rect(Rect2(rx - 2, ry - 2, 5, 5), col)
|
||
|
||
func _draw_text_centered(text: String, x: float, y: float, font_size: int, col: Color) -> void:
|
||
var font := ThemeDB.fallback_font
|
||
var tw := font.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
||
draw_string(font, Vector2(x - tw * 0.5, y + font_size), text,
|
||
HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, col)
|
||
|
||
func _draw_text(text: String, x: float, y: float, font_size: int, col: Color) -> void:
|
||
var font := ThemeDB.fallback_font
|
||
draw_string(font, Vector2(x, y + font_size), text,
|
||
HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, col)
|