## PlayerStats — 玩家属性统计(Autoload: PlayerStats) ## 权威来源:development_plan.md S2、numerical_design.md §1.2 extends Node signal stats_changed signal leveled_up(new_level: int) # ── HP ─────────────────────────────────────────────── var hp: float = 100.0 var hp_max: float = 100.0 # ── 资源 ────────────────────────────────────────────── var gold: int = 0 var xp: int = 0 # ── 等级 ────────────────────────────────────────────── var level: int = 1 var xp_to_next: int = 10 # 升级所需 XP # ── 战斗属性 ─────────────────────────────────────────── var cpu_limit: int = 5 # 控制 MAX_OPS = cpu_limit * 40 var armor: float = 0.0 var resistance: float = 0.0 # 0.0~1.0 # ── 魔力(MVP)───────────────────────────────────────── var mana: float = 100.0 var mana_max: float = 100.0 var mana_regen: float = 5.0 # 每秒回复 var mana_heat: float = 0.0 # 递增蓝耗热值(0=无,1=蓝耗翻倍) var mana_leech: float = 0.0 # 击杀回蓝量(换杖/换牌重算) func _ready() -> void: EventBus.subscribe(EventID.PLAYER_DAMAGED, _on_player_damaged) EventBus.subscribe(EventID.ENEMY_KILLED, _on_enemy_killed) func _on_enemy_killed(_payload: Dictionary) -> void: gain_mana(mana_leech) ## 升级曲线:roundf(10 × 1.4^(level-1)),P6-N16 ## Level 1→2: 10 XP; Level 5→6: ≈ 54 XP static func xp_for_level(lv: int) -> int: return roundi(10.0 * pow(1.4, float(lv - 1))) func gain_xp(amount: int) -> void: xp += amount while xp >= xp_to_next: xp -= xp_to_next level += 1 xp_to_next = xp_for_level(level) leveled_up.emit(level) EventBus.emit(EventID.LEVEL_UP, {"level": level}) stats_changed.emit() func gain_gold(amount: int) -> void: gold += amount stats_changed.emit() func spend_gold(amount: int) -> bool: if gold < amount: return false gold -= amount stats_changed.emit() return true func take_damage(amount: float) -> void: hp = max(0.0, hp - amount * SettingsManager.player_dmg_taken_mult()) # 难度减伤(初学者×0.7) stats_changed.emit() if hp <= 0.0: EventBus.emit(EventID.PLAYER_DIED, {}) func heal(amount: float) -> void: hp = min(hp_max, hp + amount) stats_changed.emit() func get_hp_percent() -> float: return hp / max(hp_max, 0.001) ## 换杖时设定蓝池上限/回速,并把当前蓝夹到 [0, max] func set_mana_pool(max_v: float, regen: float) -> void: mana_max = max_v mana_regen = regen mana = clampf(mana, 0.0, mana_max) stats_changed.emit() ## 花费魔力;够则扣除返回 true,否则不变返回 false func spend_mana(cost: float) -> bool: if mana < cost: return false mana -= cost stats_changed.emit() return true ## 每帧回蓝(PlayerManager 驱动)。不 emit stats_changed —— HUD 每帧直接读 mana, ## 避免回蓝过程每帧发信号触发商店刷新。 func regen_mana(delta: float) -> void: if mana >= mana_max: return mana = min(mana_max, mana + mana_regen * delta) ## 击杀回蓝(魔力虹吸) func gain_mana(n: float) -> void: if n <= 0.0: return mana = min(mana_max, mana + n) stats_changed.emit() ## 主动 HP 代价(infinite_spells / heavy_cost)——直接扣血,不走难度减伤 func spend_hp_cost(amount: float) -> void: if amount <= 0.0: return hp = max(0.0, hp - amount) stats_changed.emit() if hp <= 0.0: EventBus.emit(EventID.PLAYER_DIED, {}) func _on_player_damaged(payload: Dictionary) -> void: take_damage(float(payload.get("damage", 0.0))) func reset_for_run() -> void: hp = hp_max mana = mana_max gold = 0 xp = 0 level = 1 xp_to_next = xp_for_level(1) stats_changed.emit() func get_save_data() -> Dictionary: return {"hp": hp, "hp_max": hp_max, "gold": gold, "xp": xp, "level": level, "cpu_limit": cpu_limit} func load_save_data(data: Dictionary) -> void: hp = float(data.get("hp", 100.0)) hp_max = float(data.get("hp_max", 100.0)) gold = int(data.get("gold", 0)) xp = int(data.get("xp", 0)) level = int(data.get("level", 1)) cpu_limit = int(data.get("cpu_limit", 5)) xp_to_next = xp_for_level(level) stats_changed.emit()