extends RefCounted class_name ItemDB # ─── Legacy-System (alter Shop / Enemy-Upgrades in game_world.gd) ────────────── # Bleibt unverändert für Backward-Compat. Wird nur von game_world.gd für # Enemy-Stat-Boosts ab Welle 10 verwendet. enum Rarity { COMMON, UNCOMMON, RARE, EPIC } const RARITY_WEIGHTS: Array = [60, 25, 12, 3] const RARITY_COLORS: Dictionary = { 0: Color("#aaaaaa"), # COMMON 1: Color("#44ff88"), # UNCOMMON 2: Color("#4488ff"), # RARE 3: Color("#cc44ff") # EPIC } const RARITY_NAMES: Dictionary = { 0: "STANDARD", 1: "SELTEN", 2: "EPISCH", 3: "LEGENDÄR" } const ITEMS: Array = [ { "id": "thrust_1", "name": "Schubverstärker", "rarity": 0, "cost": 50, "desc": "+12% Geschwindigkeit", "effects": { "speed_mult": 1.12 } }, { "id": "firerate_1", "name": "Schnellfeuer I", "rarity": 0, "cost": 50, "desc": "+15% Feuerrate", "effects": { "fire_rate_mult": 1.15 } }, { "id": "damage_1", "name": "Schwere Ladung I", "rarity": 0, "cost": 50, "desc": "+15% Trefferzone", "effects": { "damage_mult": 1.15 } }, { "id": "shield_1", "name": "Panzerplatte", "rarity": 0, "cost": 55, "desc": "+1 Schutzladung", "effects": { "shield_charges": 1 } }, { "id": "firerate_2", "name": "Schnellfeuer II", "rarity": 1, "cost": 90, "desc": "+22% Feuerrate", "effects": { "fire_rate_mult": 1.22 } }, { "id": "damage_2", "name": "Schwere Ladung II", "rarity": 1, "cost": 100, "desc": "+22% Trefferzone +10% Projektilgeschwindigkeit", "effects": { "damage_mult": 1.22, "bullet_speed_mult": 1.10 } }, ] # Weighted random roll — Legacy-Shop (wird nicht mehr für Werkstatt verwendet) static func roll_shop(count: int, _exclude_ids: Array = []) -> Array: var pool: Array = [] for item: Dictionary in ITEMS: var w: int = RARITY_WEIGHTS[int(item["rarity"])] for _i in w: pool.append(item) pool.shuffle() var result: Array = [] var seen_ids: Dictionary = {} for item: Dictionary in pool: var iid: String = item["id"] if iid in seen_ids: continue seen_ids[iid] = true result.append(item) if result.size() >= count: break return result # ─── Werkstatt-System (Plugin-basiert) ───────────────────────────────────────── # Auto-Discovery: alle *.gd unter res://items/ die ItemDef erweitern werden # beim ersten Zugriff registriert. static var _registry: Array = [] static var _registry_loaded: bool = false # Static preload list — DirAccess doesn't work in exported builds (compiled scripts # aren't raw files in the PCK). preload() is resolved at compile time and always works. const _ITEM_SCRIPTS: Array = [ preload("res://items/weapons/wk_burst.gd"), preload("res://items/weapons/wk_charge.gd"), preload("res://items/weapons/wk_ion.gd"), preload("res://items/weapons/wk_laser.gd"), preload("res://items/weapons/wk_plasma.gd"), preload("res://items/weapons/wk_rail.gd"), preload("res://items/weapons/wk_scatter.gd"), preload("res://items/weapons/wk_shotgun.gd"), preload("res://items/weapons/wk_sniper.gd"), preload("res://items/hull/hull_giant.gd"), preload("res://items/hull/hull_nullfeld.gd"), preload("res://items/hull/hull_plating.gd"), preload("res://items/hull/hull_reaktor.gd"), preload("res://items/drives/drive_overdrive.gd"), preload("res://items/drives/drive_quantum.gd"), preload("res://items/drives/drive_steer.gd"), preload("res://items/special/special_credit_mag.gd"), preload("res://items/special/special_wipe_core.gd"), ] static func _ensure_loaded() -> void: if _registry_loaded: return _registry_loaded = true for script: Script in _ITEM_SCRIPTS: if script == null or not script.can_instantiate(): continue var inst = script.new() if inst is ItemDef and (inst as ItemDef).id != "": _registry.append(inst) static func get_all_defs() -> Array: _ensure_loaded() return _registry static func get_def_by_id(id: String) -> ItemDef: _ensure_loaded() for item in _registry: if (item as ItemDef).id == id: return item return null # Rolls `count` random items from the Werkstatt pool, excluding given IDs. static func roll_werkstatt(count: int, exclude_ids: Array = []) -> Array: _ensure_loaded() var pool: Array = [] for item in _registry: var def := item as ItemDef if exclude_ids.has(def.id): continue pool.append(def) pool.shuffle() var n: int = min(count, pool.size()) return pool.slice(0, n) # ─── Effect-Klassifizierung (für UI-Farbkodierung) ──────────────────────────── static func is_positive_effect(key: String, val) -> bool: match key: "speed_mult", "turn_mult", "fire_rate_mult", "damage_mult", \ "bullet_speed_mult", "invuln_mult", "credit_bonus": return float(val) >= 1.0 "bullet_count", "shield_charges": return int(val) > 0 "bh_resist": return float(val) > 0.0 "wipe_mult": return float(val) <= 1.0 # kleiner = schneller = besser return true # Menschlich lesbarer Stat-Name für die Vorschau. static func stat_display_name(key: String) -> String: match key: "speed_mult": return "Speed" "turn_mult": return "Wendung" "fire_rate_mult": return "Feuerrate" "damage_mult": return "Schaden" "bullet_speed_mult": return "Proj.-Speed" "bullet_count": return "Projektile" "shield_charges": return "Schilde" "invuln_mult": return "Unverwundbar" "bh_resist": return "BH-Resistenz" "wipe_mult": return "Wipe-Ladezeit" "credit_bonus": return "Kreditgewinn" return key static func get_by_id(id: String) -> Dictionary: for item: Dictionary in ITEMS: if item["id"] == id: return item return {}