Initial commit — Station 0 vertical slice in progress
Includes full design documentation (ARCHITECTURE, DESIGN_NOTES, CONTENT_SPEC, PRODUCTION_NOTES) and active Godot 4 / GDScript codebase. Core systems built: player, floor generation, room system, enemy base, body part upgrades, run manager, save system, HUD, EventBus.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
extends Resource
|
||||
class_name BodyPartData
|
||||
|
||||
@export var slot: String = "" # "head" | "torso" | "left_arm" | "right_arm" | "legs"
|
||||
@export var display_name: String = ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stat modifiers — additive bonuses stacked across all equipped parts.
|
||||
# Field names mirror the stat keys used in player_stats.gd.
|
||||
# ---------------------------------------------------------------------------
|
||||
@export var mod_speed: float = 0.0
|
||||
@export var mod_max_health: float = 0.0
|
||||
@export var mod_damage: float = 0.0
|
||||
@export var mod_fire_rate: float = 0.0
|
||||
@export var mod_range: float = 0.0
|
||||
@export var mod_proj_speed: float = 0.0 # flat delta; e.g. -104 = -20% of base 520
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Scatter (left arm slot)
|
||||
# mod_scatter_count > 0 enables multi-shot spread from this part
|
||||
# ---------------------------------------------------------------------------
|
||||
@export var mod_scatter_count: int = 0
|
||||
@export var mod_scatter_spread_deg: float = 0.0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Shield Projector (left arm slot)
|
||||
# Active block on cooldown — absorbs one hit per activation
|
||||
# ---------------------------------------------------------------------------
|
||||
@export var shield_projector: bool = false
|
||||
@@ -0,0 +1,11 @@
|
||||
extends Area2D
|
||||
|
||||
var part: BodyPartData = null
|
||||
|
||||
func _ready() -> void:
|
||||
body_entered.connect(_on_body_entered)
|
||||
|
||||
func _on_body_entered(body: Node) -> void:
|
||||
if body.is_in_group("player") and part != null:
|
||||
UpgradeManager.acquire_part(part)
|
||||
queue_free()
|
||||
@@ -0,0 +1,63 @@
|
||||
extends Node
|
||||
|
||||
const SLOTS: Array[String] = ["head", "torso", "left_arm", "right_arm", "legs"]
|
||||
|
||||
var hub_credits: int = 0
|
||||
|
||||
# slot -> BodyPart resource path (empty string = default/base part)
|
||||
var equipped_parts: Dictionary = {
|
||||
"head": "",
|
||||
"torso": "",
|
||||
"left_arm": "",
|
||||
"right_arm": "",
|
||||
"legs": "",
|
||||
}
|
||||
|
||||
# All permanently acquired part resource paths
|
||||
var acquired_part_paths: Array[String] = []
|
||||
|
||||
func equip_part(part: Resource) -> void:
|
||||
var slot: String = part.slot
|
||||
if slot not in SLOTS:
|
||||
push_error("UpgradeManager: invalid slot '%s'" % slot)
|
||||
return
|
||||
equipped_parts[slot] = part.resource_path
|
||||
EventBus.body_part_equipped.emit(part, slot)
|
||||
|
||||
func acquire_part(part: Resource) -> void:
|
||||
if part.resource_path not in acquired_part_paths:
|
||||
acquired_part_paths.append(part.resource_path)
|
||||
EventBus.body_part_found.emit(part)
|
||||
|
||||
func get_equipped_part(slot: String) -> Resource:
|
||||
var path: String = equipped_parts.get(slot, "")
|
||||
if path != "":
|
||||
return load(path)
|
||||
return null
|
||||
|
||||
func get_stat_modifier(stat: String) -> float:
|
||||
var total := 0.0
|
||||
for slot in SLOTS:
|
||||
var part := get_equipped_part(slot)
|
||||
if part == null:
|
||||
continue
|
||||
match stat:
|
||||
"speed": total += part.mod_speed
|
||||
"max_health": total += part.mod_max_health
|
||||
"damage": total += part.mod_damage
|
||||
"fire_rate": total += part.mod_fire_rate
|
||||
"range": total += part.mod_range
|
||||
"proj_speed": total += part.mod_proj_speed
|
||||
return total
|
||||
|
||||
func get_save_data() -> Dictionary:
|
||||
return {
|
||||
"equipped": equipped_parts.duplicate(),
|
||||
"acquired": acquired_part_paths.duplicate(),
|
||||
}
|
||||
|
||||
func load_save_data(data: Dictionary) -> void:
|
||||
var saved_equipped: Dictionary = data.get("equipped", {})
|
||||
for slot in SLOTS:
|
||||
equipped_parts[slot] = saved_equipped.get(slot, "")
|
||||
acquired_part_paths = data.get("acquired", [])
|
||||
Reference in New Issue
Block a user