Files
Station-0/scripts/player/player_stats.gd
T
Station 0 Dev 342175f4c3 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.
2026-03-04 12:33:05 -05:00

144 lines
5.3 KiB
GDScript

extends Node
# ---------------------------------------------------------------------------
# Base stats — no upgrades equipped
# ---------------------------------------------------------------------------
const BASE_SPEED := 200.0
const BASE_MAX_HEALTH := 6.0 # 6 HP = 3 full hearts
const BASE_DAMAGE := 3.5
const BASE_FIRE_RATE := 3.5 # shots per second
const BASE_RANGE := 400.0
const BASE_PROJ_SPEED := 520.0
# ---------------------------------------------------------------------------
# Live stats (recalculated from base + equipped parts + run items)
# ---------------------------------------------------------------------------
var speed: float = BASE_SPEED
var max_health: float = BASE_MAX_HEALTH
var current_health: float = BASE_MAX_HEALTH
var damage: float = BASE_DAMAGE
var fire_rate: float = BASE_FIRE_RATE
var range_: float = BASE_RANGE
var proj_speed: float = BASE_PROJ_SPEED
# ---------------------------------------------------------------------------
# Run-item behavior flags (recomputed each recalculate — never saved)
# ---------------------------------------------------------------------------
var ricochet: bool = false
var scatter_count: int = 1
var scatter_spread_deg: float = 0.0
var explosive: bool = false
var explosion_radius: float = 0.0
var explosion_damage: float = 0.0
# New item flags
var coolant_leak: bool = false
var scrap_magnet: bool = false
var memory_spike: bool = false
var rust_coat: bool = false
var static_discharge: bool = false
var fragmented_map: bool = false
var overclock: bool = false
var damage_reduction: float = 0.0
var discharge_radius: float = 64.0
var discharge_damage: float = 1.0
var magnet_radius: float = 0.0
# ---------------------------------------------------------------------------
# Body-part behavior flags (recomputed each recalculate)
# ---------------------------------------------------------------------------
var shield_projector: bool = false
func _ready() -> void:
EventBus.body_part_equipped.connect(_on_part_equipped)
recalculate()
if RunManager.player_health_carry > 0.0:
current_health = minf(RunManager.player_health_carry, max_health)
RunManager.player_health_carry = -1.0
func recalculate() -> void:
speed = BASE_SPEED + UpgradeManager.get_stat_modifier("speed")
max_health = BASE_MAX_HEALTH + UpgradeManager.get_stat_modifier("max_health")
damage = BASE_DAMAGE + UpgradeManager.get_stat_modifier("damage")
fire_rate = BASE_FIRE_RATE + UpgradeManager.get_stat_modifier("fire_rate")
range_ = BASE_RANGE + UpgradeManager.get_stat_modifier("range")
proj_speed = BASE_PROJ_SPEED + UpgradeManager.get_stat_modifier("proj_speed")
_apply_run_items()
_apply_part_flags()
current_health = minf(current_health, max_health)
func _apply_run_items() -> void:
ricochet = false
scatter_count = 1
scatter_spread_deg = 0.0
explosive = false
explosion_radius = 0.0
explosion_damage = 0.0
coolant_leak = false
scrap_magnet = false
memory_spike = false
rust_coat = false
static_discharge = false
fragmented_map = false
overclock = false
damage_reduction = 0.0
discharge_radius = 64.0
discharge_damage = 1.0
magnet_radius = 0.0
for item: RunItem in RunManager.run_items:
match item.effect:
RunItem.Effect.STAT_MOD:
match item.stat_key:
"speed": speed += item.stat_delta
"max_health": max_health += item.stat_delta
"damage": damage += item.stat_delta
"fire_rate": fire_rate += item.stat_delta
"range": range_ += item.stat_delta
RunItem.Effect.RICOCHET:
ricochet = true
RunItem.Effect.SCATTER:
scatter_count = maxi(scatter_count, item.scatter_count)
scatter_spread_deg = maxf(scatter_spread_deg, item.scatter_spread_deg)
RunItem.Effect.EXPLOSIVE:
explosive = true
explosion_radius = maxf(explosion_radius, item.explosion_radius)
explosion_damage = maxf(explosion_damage, item.explosion_damage)
RunItem.Effect.COOLANT_LEAK:
coolant_leak = true
RunItem.Effect.SCRAP_MAGNET:
scrap_magnet = true
magnet_radius = maxf(magnet_radius, item.magnet_radius)
RunItem.Effect.MEMORY_SPIKE:
memory_spike = true
RunItem.Effect.RUST_COAT:
rust_coat = true
damage_reduction = maxf(damage_reduction, item.damage_reduction)
RunItem.Effect.STATIC_DISCHARGE:
static_discharge = true
discharge_radius = maxf(discharge_radius, item.discharge_radius)
discharge_damage = maxf(discharge_damage, item.discharge_damage)
RunItem.Effect.FRAGMENTED_MAP:
fragmented_map = true
RunItem.Effect.OVERCLOCK:
overclock = true
fire_rate *= 1.4
func _apply_part_flags() -> void:
shield_projector = false
# Scatter from body parts (accumulate with run item scatter)
for slot in UpgradeManager.SLOTS:
var part := UpgradeManager.get_equipped_part(slot)
if part == null:
continue
if part.shield_projector:
shield_projector = true
if part.mod_scatter_count > 0:
scatter_count = maxi(scatter_count, part.mod_scatter_count)
scatter_spread_deg = maxf(scatter_spread_deg, part.mod_scatter_spread_deg)
func heal(amount: float) -> void:
current_health = minf(current_health + amount, max_health)
func _on_part_equipped(_part: Resource, _slot: String) -> void:
recalculate()