dispatcher = $dispatcher; $this->stateManager = $stateManager; $this->input = $input; $this->output = $output; $this->helper = $helper; } public function handleEvent(Event $event): void { if ($this->inBattle) { switch ($event->getType()) { case 'AbilityEffectApplied': // ⭐ 监听技能施放效果 $target = $event->getPayload()['target']; if ($target instanceof Enemy && !$target->isAlive()) { $this->handleWin(); return; // 战斗结束 } // 如果是玩家治疗,则无需返回 break; } return; } switch ($event->getType()) { case 'StartBattleEvent': // 收到 MapSystem 触发的战斗开始事件 $enemyId = $event->getPayload()['enemyId']; $this->startBattle($enemyId); break; } } /** * 1. 初始化战斗状态 */ private function startBattle(int $enemyId): void { // ... 初始化敌人逻辑 (继承自 Character) ... $enemyData = $this->loadEnemyData($enemyId); $this->currentEnemy = new Enemy( (string)$enemyId, $enemyData['name'], $enemyData['health'], $enemyData['attack'], $enemyData['defense'], $enemyData['xp'] ); $this->inBattle = true; $this->dispatcher->dispatch(new Event('SystemMessage', [ 'message' => "⚔️ 你遭遇了 {$this->currentEnemy->getName()}!战斗开始!" ])); // 立即进入战斗循环 $this->battleLoop(); } /** * 2. 核心战斗循环 */ private function battleLoop(): void { while ($this->inBattle) { // 确保 UI 服务打印了战斗状态 $this->dispatcher->dispatch(new Event('ShowBattleStatsEvent', [ 'enemy' => $this->currentEnemy, 'player' => $this->stateManager->getPlayer(), ])); // 玩家回合 (阻塞输入) $playerAction = $this->promptPlayerAction(); if ($playerAction === 'A') { $this->playerAttack(); }elseif ($playerAction === 'C') { // ⭐ 施法逻辑 $this->handleAbilityInput(); } elseif ($playerAction === 'R') { if ($this->tryRunAway()) { $this->endBattle(false); return; } } if (!$this->inBattle) break; // 敌人回合 $this->enemyAttack(); if (!$this->inBattle) break; } } private function handleAbilityInput(): void { $player = $this->stateManager->getPlayer(); $abilities = $player->getAbilities(); if (empty($abilities)) { $this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '你还没有学会任何技能!'])); return; } $this->output->writeln("\n--- 魔法技能 ---"); $availableIds = []; foreach ($abilities as $id => $ability) { $canCast = $player->getMana() >= $ability->manaCost ? "" : ""; $this->output->writeln(" [{$id}] {$ability->name} | 消耗: {$canCast}{$ability->manaCost} MP"); $availableIds[] = $id; } $this->output->writeln("----------------"); $question = new Question("> 请输入技能 ID (或 X 取消):"); $choice = strtoupper($this->helper->ask($this->input, $this->output, $question) ?? ''); if ($choice === 'X') return; if (in_array($choice, $availableIds)) { // ⭐ 触发事件,将处理权交给 AbilityService $this->dispatcher->dispatch(new Event('CastAbilityEvent', [ 'abilityId' => $choice, 'target' => $this->currentEnemy // 暂定为当前敌人 ])); } else { $this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '无效的技能 ID。'])); } } /** * 获取玩家战斗指令 (直接使用注入的 I/O 接口) */ private function promptPlayerAction(): string { $this->dispatcher->dispatch(new Event('SystemMessage', [ 'message' => "\n--- 你的回合 --- [A] 攻击 | [C] 施法 | [R] 逃跑" // ⭐ 增加 C ])); $question = new Question("> 请选择指令 (A/C/R):"); // 关键:使用注入的 I/O 接口 $choice = strtoupper($this->helper->ask($this->input, $this->output, $question) ?? ''); // 简单的输入验证 if (in_array($choice, ['A', 'C', 'R'])) { // ⭐ 增加 C return $choice; } else { $this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '无效的战斗指令。'])); return $this->promptPlayerAction(); } } /** * 玩家攻击逻辑 */ private function playerAttack(): void { $player = $this->stateManager->getPlayer(); $rawDamage = $player->getAttack(); $actualDamage = $this->currentEnemy->takeDamage($rawDamage); $this->dispatcher->dispatch(new Event('SystemMessage', [ 'message' => "⚡ 你对 {$this->currentEnemy->getName()} 造成了 {$actualDamage} 点伤害!" ])); if (!$this->currentEnemy->isAlive()) { $this->handleWin(); } } /** * 敌人攻击逻辑 */ private function enemyAttack(): void { $player = $this->stateManager->getPlayer(); $rawDamage = $this->currentEnemy->getAttack(); // Player 的 takeDamage 会更新 StateManager 中的 Player 实例 $actualDamage = $player->takeDamage($rawDamage); $this->dispatcher->dispatch(new Event('SystemMessage', [ 'message' => "💥 {$this->currentEnemy->getName()} 对你造成了 {$actualDamage} 点伤害!" ])); if (!$player->isAlive()) { $this->handleLoss(); } } /** * 尝试逃跑 */ private function tryRunAway(): bool { if (rand(1, 100) > 50) { $this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "💨 你成功逃离了战斗!"])); return true; } else { $this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "被 {$this->currentEnemy->getName()} 拦住了!逃跑失败。"])); return false; } } /** * 3. 战斗胜利处理 */ private function handleWin(): void { $xpGained = $this->currentEnemy->getXpValue(); $this->dispatcher->dispatch(new Event('SystemMessage', [ 'message' => "🏆 恭喜你击败了 {$this->currentEnemy->getName()}!" ])); // 触发 XP 和 Loot 事件,交由其他系统处理 $this->dispatcher->dispatch(new Event('XpGainedEvent', ['xp' => $xpGained])); $this->dispatcher->dispatch(new Event('LootDropEvent', ['enemyId' => $this->currentEnemy->getId()])); $this->endBattle(true); } /** * 4. 战斗失败处理 */ private function handleLoss(): void { $this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "💀 你被击败了... 游戏结束。"])); // TODO: 触发 GameEndEvent 或 RespawnEvent $this->endBattle(false); } /** * 结束战斗状态 */ private function endBattle(bool $isWin): void { $this->inBattle = false; $this->currentEnemy = null; // 战斗结束后,重新打印主菜单请求,以继续主循环 $this->dispatcher->dispatch(new Event('ShowMenuEvent')); } /** * 模拟从配置中加载敌人数据 */ private function loadEnemyData(int $id): array { // 在实际项目中,这应该从数据库或 JSON 文件加载 return match ($id) { 1 => ['name' => '弱小的哥布林', 'health' => 20, 'attack' => 5, 'defense' => 1, 'xp' => 10], 2 => ['name' => '愤怒的野猪', 'health' => 35, 'attack' => 8, 'defense' => 3, 'xp' => 25], 3 => ['name' => '森林狼', 'health' => 40, 'attack' => 10, 'defense' => 5, 'xp' => 40], default => ['name' => '未知生物', 'health' => 1, 'attack' => 1, 'defense' => 0, 'xp' => 1], }; } }