fanren/src/System/ShopService.php
2025-12-16 13:49:05 +08:00

195 lines
7.5 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\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("--------------------------");
}
}