fanren/src/System/InteractionSystem.php
2025-12-15 23:02:21 +08:00

137 lines
4.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Game\System;
use Game\Event\Event;
use Game\Event\EventListenerInterface;
use Game\Event\EventDispatcher;
use Game\Model\NPC;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Question\Question;
/**
* InteractionSystem: 负责处理玩家与 NPC 的对话和交互流程。
*/
class InteractionSystem implements EventListenerInterface {
private EventDispatcher $dispatcher;
private StateManager $stateManager;
// 输入依赖
private InputInterface $input;
private OutputInterface $output;
private QuestionHelper $helper;
public function __construct(EventDispatcher $dispatcher, StateManager $stateManager, InputInterface $input, OutputInterface $output, QuestionHelper $helper) {
$this->dispatcher = $dispatcher;
$this->stateManager = $stateManager;
$this->input = $input;
$this->output = $output;
$this->helper = $helper;
}
public function handleEvent(Event $event): void {
switch ($event->getType()) {
case 'AttemptInteractEvent':
// 假设 MapSystem 会提供当前 Tile 上的 NPC ID
$npcId = $event->getPayload()['npcId'];
$this->startInteraction($npcId);
break;
}
}
/**
* 1. 初始化 NPC 交互
*/
private function startInteraction(string $npcId): void {
$npc = $this->loadNPC($npcId);
if (!$npc) {
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "这里没有人可以交谈。"]));
return;
}
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => "👤 你走近了 <fg=cyan;options=bold>{$npc->getName()}</>。"
]));
// 启动对话流程
$this->dialogueLoop($npc);
// 交互结束后,重新打印主菜单请求
$this->dispatcher->dispatch(new Event('ShowMenuEvent'));
}
/**
* 2. 核心对话循环
*/
private function dialogueLoop(NPC $npc): void {
$currentDialogueKey = 'greeting';
$running = true;
while ($running) {
// 打印 NPC 对话
$text = $npc->getDialogueText($currentDialogueKey);
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => "<fg=cyan>{$npc->getName()}</><fg=white>{$text}</>"
]));
// 检查交互类型并获取玩家选择
$choice = $this->promptPlayerChoice();
switch ($choice) {
case 'T': // 触发任务/特殊事件
$this->dispatcher->dispatch(new Event('QuestCheckEvent', ['npcId' => $npc->id]));
$currentDialogueKey = 'quest_response';
break;
case 'S': // 触发商店
$this->dispatcher->dispatch(new Event('OpenShopEvent', ['npcId' => $npc->id]));
$currentDialogueKey = 'shop_response';
break;
case 'E': // 结束对话
$running = false;
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "🤝 你结束了与 {$npc->getName()} 的对话。"]));
break;
default:
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '无效的交互指令。']));
}
}
}
/**
* 获取玩家交互指令
*/
private function promptPlayerChoice(): string {
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => "\n--- 交互菜单 --- [T] 任务 | [S] 商店 | [E] 结束"
]));
$question = new Question("> 请选择指令 (T/S/E)");
$choice = strtoupper($this->helper->ask($this->input, $this->output, $question) ?? '');
return $choice;
}
/**
* 模拟从配置中加载 NPC 数据
*/
private function loadNPC(string $id): ?NPC {
$data = match ($id) {
'VILLAGER_1' => [
'name' => '老村长',
'dialogue' => [
'greeting' => '你好,旅行者。你看起来很强大。',
'quest_response' => '你想要帮忙吗?我们的地窖里有老鼠。',
'shop_response' => '我现在没有东西卖给你。',
]
],
default => null,
};
if ($data) {
return new NPC($id, $data['name'], $data['dialogue']);
}
return null;
}
}