Initial commit — Godot space roguelite source

- 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>
This commit is contained in:
2026-04-21 14:38:09 +02:00
commit edc40f9008
108 changed files with 10068 additions and 0 deletions
+167
View File
@@ -0,0 +1,167 @@
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)