player = new Player(); $this->savesDir = __DIR__ . '/../../saves'; // 确保存档目录存在 if (!is_dir($this->savesDir)) { mkdir($this->savesDir, 0755, true); } // 设置用户ID和存档路径 if ($userId) { $this->userId = $userId; $this->saveFile = $this->savesDir . '/' . $userId . '.json'; } else { // 向后兼容:单机模式使用默认存档 $this->saveFile = __DIR__ . '/../../save.json'; } $this->loadState(); } /** * 获取当前用户ID */ public function getUserId(): ?string { return $this->userId; } private function loadState(): void { if (file_exists($this->saveFile)) { $data = json_decode(file_get_contents($this->saveFile), true); if (is_array($data)) { $p = $data['player'] ?? []; $this->player->hp = $p['hp'] ?? $this->player->hp; $this->player->maxHp = $p['maxHp'] ?? $this->player->maxHp; // 新属性系统,向后兼容旧存档 $this->player->patk = $p['patk'] ?? $p['atk'] ?? $this->player->patk; $this->player->matk = $p['matk'] ?? $this->player->matk; $this->player->pdef = $p['pdef'] ?? $p['def'] ?? $this->player->pdef; $this->player->mdef = $p['mdef'] ?? $this->player->mdef; $this->player->crit = $p['crit'] ?? $this->player->crit; $this->player->critdmg = $p['critdmg'] ?? $this->player->critdmg; $this->player->level = $p['level'] ?? $this->player->level; $this->player->exp = $p['exp'] ?? $this->player->exp; $this->player->maxExp = $p['maxExp'] ?? $this->player->maxExp; $this->player->inventory = $p['inventory'] ?? $this->player->inventory; $this->player->equip = $p['equip'] ?? $this->player->equip; $this->player->spiritStones = $p['spiritStones'] ?? $this->player->spiritStones; $this->player->npcFlags = $p['npcFlags'] ?? $this->player->npcFlags; // 加载天赋数据 $this->player->talentPoints = $p['talentPoints'] ?? $this->player->talentPoints; $this->player->talents = $p['talents'] ?? $this->player->talents; // 加载同伴数据 if (isset($p['partners']) && is_array($p['partners'])) { foreach ($p['partners'] as $partnerData) { $partner = new Partner($partnerData); $this->player->partners[$partner->id] = $partner; } } // 加载技能槽位数据 (新法术系统) $this->player->mana = $p['mana'] ?? $this->player->mana; $this->player->maxMana = $p['maxMana'] ?? $this->player->maxMana; $this->player->skillSlots = $p['skillSlots'] ?? $this->player->skillSlots; $this->dungeonId = $data['dungeonId'] ?? $this->dungeonId; $this->state = self::MENU; } } } public function saveState(): void { // 序列化同伴数据 $partnersData = []; foreach ($this->player->partners as $partner) { $partnersData[] = [ 'id' => $partner->id, 'name' => $partner->name, 'level' => $partner->level, 'exp' => $partner->exp, 'maxExp' => $partner->maxExp, 'equip' => $partner->equip, 'talents' => $partner->talents, 'talentWeights' => $partner->talentWeights, 'mana' => $partner->mana, 'maxMana' => $partner->maxMana, 'skillSlots' => $partner->skillSlots, 'hp' => $partner->hp, 'maxHp' => $partner->maxHp, 'patk' => $partner->patk, 'matk' => $partner->matk, 'pdef' => $partner->pdef, 'mdef' => $partner->mdef, 'crit' => $partner->crit, 'critdmg' => $partner->critdmg, ]; } $data = [ 'player' => [ 'hp' => $this->player->hp, 'maxHp' => $this->player->maxHp, 'patk' => $this->player->patk, 'matk' => $this->player->matk, 'pdef' => $this->player->pdef, 'mdef' => $this->player->mdef, 'crit' => $this->player->crit, 'critdmg' => $this->player->critdmg, 'level' => $this->player->level, 'exp' => $this->player->exp, 'maxExp' => $this->player->maxExp, 'inventory' => $this->player->inventory, 'equip' => $this->player->equip, 'spiritStones' => $this->player->spiritStones, 'npcFlags' => $this->player->npcFlags, 'talentPoints' => $this->player->talentPoints, 'talents' => $this->player->talents, 'mana' => $this->player->mana, 'maxMana' => $this->player->maxMana, 'skillSlots' => $this->player->skillSlots, 'partners' => $partnersData, ], 'dungeonId' => $this->dungeonId, 'state' => $this->state, ]; file_put_contents($this->saveFile, json_encode($data, JSON_UNESCAPED_UNICODE)); } public function run() { while (true) { switch ($this->state) { case self::MENU: (new Menu($this))->show(); break; case self::DUNGEON_SELECT: (new DungeonSelectPanel($this))->show(); break; case self::BATTLE: (new Battle($this))->start(); break; case self::STATS: (new StatsPanel($this))->show(); break; case self::INVENTORY: (new InventoryPanel($this))->show(); break; case self::NPC: (new NpcPanel($this))->show(); break; case self::TALENT: (new TalentPanel($this))->show(); break; case self::EQUIPMENT_ENHANCE: (new EquipmentEnhancePanel($this))->show(); break; case self::EXIT: $this->output->writeln("再见!"); $this->saveState(); return; } } } }