fanren/src/System/LootService.php
2025-12-24 21:10:08 +08:00

179 lines
6.3 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\Database\EnemyRepository;
use Game\Database\ItemRepository;
use Game\Event\Event;
use Game\Event\EventListenerInterface;
use Game\Event\EventDispatcher;
use Game\Model\Enemy;
use Game\Model\Item;
/**
* LootService: 负责处理物品掉落、背包管理和物品获取。
*/
class LootService implements EventListenerInterface {
private EventDispatcher $dispatcher;
private StateManager $stateManager;
// ... 现有属性 ...
private ItemRepository $itemRepository;
private EnemyRepository $enemyRepository;
// ⭐ 修正构造函数:注入 Repositories
public function __construct(EventDispatcher $dispatcher, StateManager $stateManager, ItemRepository $itemRepository, EnemyRepository $enemyRepository) {
$this->dispatcher = $dispatcher;
$this->stateManager = $stateManager;
$this->itemRepository = $itemRepository;
$this->enemyRepository = $enemyRepository;
}
public function createEnemy(string $id): ?Enemy {
// ⭐ 使用 Repository 获取数据
$data = $this->enemyRepository->find($id);
if (!$data) {
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "❌ 错误敌人ID '{$id}' 不存在。"]));
return null;
}
// ⭐ 修正实例化 Enemy传入 loot_table
return new Enemy(
$data['id'],
$data['name'],
$data['health'],
$data['attack'],
$data['defense'],
$data['xp'],
$data['loot'] ?? [] // 传递 loot_table
);
}
public function handleEvent(Event $event): void {
switch ($event->getType()) {
case 'LootDropEvent':
$enemyId = $event->getPayload()['enemyId'];
// LootDropEvent 应该由 BattleService 在敌人死亡时触发
$this->handleLootDrop($enemyId);
break;
case 'LootFoundEvent': // 响应 MapSystem 探索时发现的宝箱
$lootId = $event->getPayload()['lootId'];
$this->handleLootFound($lootId);
break;
case 'ShopPurchaseEvent': // ⭐ 响应商店购买
$itemId = $event->getPayload()['itemId'];
$this->giveItemToPlayer($itemId);
break;
// ⭐ 响应遇敌事件
case 'EncounterEnemyEvent':
$enemyId = $event->getPayload()['enemyId'];
$newEnemy = $this->createEnemy($enemyId);
if ($newEnemy) {
// 通知 BattleService 启动战斗
$this->dispatcher->dispatch(new Event('StartBattleEvent', ['enemy' => $newEnemy]));
}
break;
}
}
/**
* ⭐ 修正方法:处理敌人死亡时的掉落逻辑(从配置中加载数据)
*/
private function handleLootDrop(string $enemyId): void {
// 1. 获取敌人配置数据
$enemyData = $this->enemyRepository->find($enemyId);
if (!$enemyData) {
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "❌ 错误:无法找到敌人 {$enemyId} 的掉落配置。"]));
return;
}
// --- 2. 掉落金币 (从配置中获取范围) ---
$minGold = $enemyData['min_gold'] ?? 5; // 使用配置,默认 5
$maxGold = $enemyData['max_gold'] ?? 15; // 使用配置,默认 15
$goldAmount = rand($minGold, $maxGold);
$player = $this->stateManager->getPlayer();
$player->gainGold($goldAmount);
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => "💰 获得了 <fg=yellow>{$goldAmount}</> 金币。"
]));
// --- 3. 掉落物品 (从配置的 loot_table 中获取) ---
$lootTable = $enemyData['loot_table'] ?? [];
if (!empty($lootTable)) {
$droppedItemId = $this->getRandomItemIdFromLootTable($lootTable);
if ($droppedItemId !== null) { // 成功掉落物品
$this->giveItemToPlayer($droppedItemId);
} else {
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => "战利品很少,只找到了一些零钱。"
]));
}
} else {
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => "战利品很少,只找到了一些零钱。"
]));
}
}
/**
* ⭐ 新增方法:根据权重随机选择物品 ID
*/
private function getRandomItemIdFromLootTable(array $lootTable): ?int {
$totalChance = array_sum(array_column($lootTable, 'chance'));
// 随机数范围是 1 到 100
$randValue = rand(1, 100);
// 如果随机值大于总几率,则表示未掉落任何物品
// 例如:总几率为 80随机数是 85则不掉落
if ($randValue > $totalChance) {
return null;
}
$currentChance = 0;
foreach ($lootTable as $item) {
$currentChance += $item['chance'];
if ($randValue <= $currentChance) {
// 确保 item_id 是整数类型
return (int)$item['item_id'];
}
}
return null;
}
/**
* 处理探索时发现的宝箱/固定物品 (保持不变)
*/
private function handleLootFound($lootId): void {
}
/**
* 核心逻辑:创建物品实例并添加到玩家背包 (保持不变)
*/
private function giveItemToPlayer($itemId): void {
// ...
$item = $this->itemRepository->createItem($itemId);
if (!$item) {
$this->dispatcher->dispatch(new Event('SystemMessage', ['message' => "❌ 物品ID '{$itemId}' 不存在,无法获得。"]));
return;
}
$player = $this->stateManager->getPlayer();
$player->addItem($item);
$this->dispatcher->dispatch(new Event('SystemMessage', [
'message' => " 获得了物品:<fg=green>{$item->name}</>"
]));
// 触发 InventoryUpdateEvent (未来用于 UI 实时更新)
$this->dispatcher->dispatch(new Event('InventoryUpdateEvent', ['playerInventory' => $player->getInventory()]));
}
}