195 lines
7.5 KiB
PHP
195 lines
7.5 KiB
PHP
<?php
|
||
namespace Game\System;
|
||
|
||
use Game\Event\Event;
|
||
use Game\Event\EventListenerInterface;
|
||
use Game\Event\EventDispatcher;
|
||
use Game\Model\Item;
|
||
use Game\Model\Player;
|
||
use Symfony\Component\Console\Input\InputInterface;
|
||
use Symfony\Component\Console\Output\OutputInterface;
|
||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||
use Symfony\Component\Console\Question\Question;
|
||
|
||
/**
|
||
* ShopService: 负责处理商店的购买和出售交易。
|
||
*/
|
||
class ShopService implements EventListenerInterface {
|
||
|
||
private EventDispatcher $dispatcher;
|
||
private StateManager $stateManager;
|
||
private InputInterface $input;
|
||
private OutputInterface $output;
|
||
private QuestionHelper $helper;
|
||
|
||
// 商店的固定库存(通常从配置加载)
|
||
private array $shopInventory;
|
||
|
||
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;
|
||
$this->loadShopInventory();
|
||
}
|
||
|
||
private function loadShopInventory(): void {
|
||
// 模拟商店出售的物品配置 (ID 对应 LootService::loadItemData)
|
||
$this->shopInventory = [
|
||
// 商店物品 ID => 价格倍数(如果价格不是 Item::value)
|
||
1 => ['stock' => 10, 'price' => 10], // 小药水
|
||
3 => ['stock' => 5, 'price' => 100], // 新物品:高级药水
|
||
];
|
||
}
|
||
|
||
public function handleEvent(Event $event): void {
|
||
switch ($event->getType()) {
|
||
case 'OpenShopEvent': // 响应 InteractionSystem 的请求
|
||
$this->startShopping();
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 启动商店界面和循环
|
||
*/
|
||
private function startShopping(): void {
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "\n欢迎光临!看看我有什么好东西。"]));
|
||
$running = true;
|
||
|
||
while ($running) {
|
||
$player = $this->stateManager->getPlayer();
|
||
$this->displayShopMenu($player);
|
||
|
||
$question = new Question("> 请选择操作 (B:购买 | S:出售 | X:退出):");
|
||
$choice = strtoupper($this->helper->ask($this->input, $this->output, $question) ?? '');
|
||
|
||
switch ($choice) {
|
||
case 'B':
|
||
$this->handlePurchase();
|
||
break;
|
||
case 'S':
|
||
$this->handleSelling();
|
||
break;
|
||
case 'X':
|
||
$running = false;
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '下次再来!']));
|
||
break;
|
||
default:
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '无效的指令。']));
|
||
}
|
||
}
|
||
}
|
||
|
||
// --- 购买逻辑 ---
|
||
|
||
private function handlePurchase(): void {
|
||
$this->displaySaleItems();
|
||
$player = $this->stateManager->getPlayer();
|
||
|
||
$question = new Question("> 输入要购买的物品编号 (或 X 退出):");
|
||
$choice = strtoupper($this->helper->ask($this->input, $this->output, $question) ?? '');
|
||
|
||
if ($choice === 'X') return;
|
||
|
||
if (is_numeric($choice)) {
|
||
$itemId = (int)$choice;
|
||
if (isset($this->shopInventory[$itemId])) {
|
||
$price = $this->shopInventory[$itemId]['price'];
|
||
|
||
if ($player->spendGold($price)) {
|
||
// ⭐ 触发事件请求 LootService 给予物品(重用 LootService 的逻辑)
|
||
$this->dispatcher->dispatch(new Event('ShopPurchaseEvent', ['itemId' => $itemId]));
|
||
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', [
|
||
'message' => "交易成功!花费 {$price} 💰,剩余 {$player->getGold()} 💰。"
|
||
]));
|
||
} else {
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "金币不足!你需要 {$price} 💰。"]));
|
||
}
|
||
} else {
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '商店没有这个编号的物品。']));
|
||
}
|
||
}
|
||
}
|
||
|
||
// --- 出售逻辑 ---
|
||
|
||
private function handleSelling(): void {
|
||
$player = $this->stateManager->getPlayer();
|
||
if (empty($player->getInventory())) {
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '你的背包是空的,没有什么可卖的。']));
|
||
return;
|
||
}
|
||
|
||
$this->displaySellableItems($player);
|
||
|
||
$question = new Question("> 输入要出售的物品编号 (背包索引 | 或 X 退出):");
|
||
$choice = strtoupper($this->helper->ask($this->input, $this->output, $question) ?? '');
|
||
|
||
if ($choice === 'X') return;
|
||
|
||
if (is_numeric($choice)) {
|
||
$index = (int)$choice;
|
||
$inventory = $player->getInventory();
|
||
|
||
if (isset($inventory[$index])) {
|
||
$item = $inventory[$index];
|
||
// 简化:出售价格为 Item::value 的一半
|
||
$sellPrice = floor($item->value / 2);
|
||
|
||
// 移除物品并获得金币
|
||
$player->removeItemByIndex($index);
|
||
$player->gainGold($sellPrice);
|
||
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', [
|
||
'message' => "💰 出售了 <fg=white>{$item->name}</>,获得 {$sellPrice} 💰。剩余 {$player->getGold()} 💰。"
|
||
]));
|
||
|
||
// 触发 UI 更新
|
||
$this->dispatcher->dispatch(new Event('InventoryUpdateEvent'));
|
||
|
||
} else {
|
||
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => '无效的背包编号。']));
|
||
}
|
||
}
|
||
}
|
||
|
||
// --- UI 辅助方法 ---
|
||
|
||
private function displayShopMenu(Player $player): void {
|
||
$this->output->writeln("\n--- 商店主页 ---");
|
||
$this->output->writeln("你的金币: <fg=yellow>{$player->getGold()}</> 💰");
|
||
$this->output->writeln("--------------------------");
|
||
}
|
||
|
||
private function displaySaleItems(): void {
|
||
$this->output->writeln("\n--- 🛒 商店出售 ---");
|
||
// 模拟获取 Item 数据的服务(实际应通过 ItemService/DB)
|
||
$itemsData = [
|
||
1 => ['name' => '小型治疗药水', 'value' => 10, 'type' => 'potion'],
|
||
3 => ['name' => '高级治疗药水', 'value' => 200, 'type' => 'potion'], // 假设 ID 3
|
||
];
|
||
|
||
foreach ($this->shopInventory as $itemId => $data) {
|
||
$name = $itemsData[$itemId]['name'] ?? "未知物品";
|
||
$price = $data['price'];
|
||
$this->output->writeln("[<fg=green>{$itemId}</>] {$name} | 价格: <fg=yellow>{$price}</> 💰");
|
||
}
|
||
$this->output->writeln("--------------------------");
|
||
}
|
||
|
||
private function displaySellableItems(Player $player): void {
|
||
$this->output->writeln("\n--- 📦 出售你的物品 ---");
|
||
$inventory = $player->getInventory();
|
||
|
||
if (empty($inventory)) return;
|
||
|
||
foreach ($inventory as $index => $item) {
|
||
$sellPrice = floor($item->value / 2);
|
||
$this->output->writeln("[<fg=green>{$index}</>] <fg=white>{$item->name}</> | 售价: <fg=yellow>{$sellPrice}</> 💰");
|
||
}
|
||
$this->output->writeln("--------------------------");
|
||
}
|
||
} |