This commit is contained in:
hant 2025-12-08 23:25:06 +08:00
parent 5136e55932
commit b022abd6a9
8 changed files with 852 additions and 788 deletions

View File

@ -24,13 +24,14 @@ class ItemDisplay
// 类型名称
private static array $typeNames = [
'weapon' => '武器',
'armor' => '护甲',
'boots' => '靴子',
'ring' => '戒指',
'necklace' => '项链',
'consume' => '消耗品',
'spell' => '法术',
'weapon' => '武器',
'armor' => '护甲',
'boots' => '靴子',
'ring' => '戒指',
'necklace' => '项链',
'consume' => '消耗品',
'spell' => '法术',
'quest_item' => '任务物品',
];
// 属性名称
@ -84,6 +85,11 @@ class ItemDisplay
*/
public static function formatName(array $item): string
{
// 任务物品不显示等级
if (($item['type'] ?? '') === 'quest_item') {
return self::$magenta . $item['name'] . self::$reset;
}
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
$color = self::getQualityColor($quality);
$name = ($item['name'] ?? '未知物品') . 'lv.' . $item['level'];
@ -212,6 +218,17 @@ class ItemDisplay
// 主属性(简洁版)或法术信息
$type = $item['type'] ?? '';
// 特殊处理任务物品
if ($type === 'quest_item') {
$parts = [];
$parts[] = self::$magenta . "【任务物品】" . self::$reset . " {$item['name']}";
if ($showType) {
$parts[] = self::$gray . "[任务物品]" . self::$reset;
}
return implode(" ", $parts);
}
if ($type === 'spell') {
// 法术显示由 SpellDisplay 处理(计算方式和基础数值)
// 需要导入 SpellDisplay 后使用
@ -270,6 +287,17 @@ class ItemDisplay
$type = $item['type'] ?? '';
$typeName = self::getTypeName($type);
// 特殊处理任务物品
if ($type === 'quest_item') {
$lines[] = $linePrefix . self::$magenta . "【任务物品】" . self::$reset . " {$item['name']}";
$lines[] = $linePrefix;
$lines[] = $linePrefix . "这是一个关键任务物品,";
$lines[] = $linePrefix . "用于解锁新的探险区域。";
$lines[] = $linePrefix;
$lines[] = $linePrefix . "无法装备、无法出售、无法交易。";
return $lines;
}
$enhanceLevel = $item['enhanceLevel'] ?? 0;
// 名称行
@ -371,6 +399,11 @@ class ItemDisplay
*/
public static function renderDrop(array $item, string $prefix = " "): string
{
// 特殊处理任务物品
if ($item['type'] === 'quest_item') {
return $prefix . "📜 " . self::$magenta . "【任务物品】" . self::$reset . " {$item['name']}";
}
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
$color = self::getQualityColor($quality);
if ($item['type'] == 'potion_pool'){

File diff suppressed because it is too large Load Diff

View File

@ -243,11 +243,11 @@ class Actor
{
// 多项式公式,避免过度指数增长
// base: 100 (1级升2级的基础经验)
// linear: 10 * level (线性增长部分)
// quadratic: 0.5 * level² (二次增长部分增长速度比1.2x指数慢得多)
// linear: 100 * level (线性增长部分)
// quadratic: level * $level * $level (二次增长部分增长速度比1.2x指数慢得多)
$base = 100;
$linear = 10 * $level;
$quadratic = (int)(0.5 * $level * $level);
$linear = 100 * $level;
$quadratic = (int)($level * $level * $level);
return $base + $linear + $quadratic;
}

View File

@ -232,6 +232,24 @@ class Item
return self::createFromSpec($spec, $baseLevel);
}
/**
* 创建任务道具 - 用于地图解锁的特殊物品
* @param string $name 任务物品名称
* @return array 任务物品数组
*/
public static function createQuestItem(string $name): array
{
return [
'id' => uniqid('quest_'),
'type' => 'quest_item',
'name' => $name,
'quality' => 'legendary',
'level' => 1,
'quantity' => 1,
'desc' => '关键任务物品,用于解锁新区域',
];
}
/**
* 创建法术物品 - 支持新的丰富法术系统
* @param int $spellId 法术ID

View File

@ -152,6 +152,16 @@ class Monster extends Actor
$type = $drop['type'] ?? '';
$rate = $drop['rate'] ?? 0;
// 处理任务物品
if ($type === 'quest_item') {
$item = Item::createQuestItem($drop['name'] ?? '未知道具');
$this->dropTable[] = [
'item' => $item,
'rate' => $rate,
];
continue;
}
if ($type === 'consume') {
$spec = $drop;
unset($spec['rate']);

View File

@ -9,6 +9,33 @@ class DungeonSelectPanel
{
public function __construct(public Game $game) {}
/**
* 检查玩家是否拥有指定物品
*/
private function hasItem(string $itemName): bool
{
foreach ($this->game->player->inventory as $item) {
if (($item['name'] ?? '') === $itemName) {
return true;
}
}
return false;
}
/**
* 检查玩家是否可以进入某个副本
*/
private function canEnterDungeon(array $map): bool
{
// 如果没有key_item要求可以进入
if ($map['key_item'] === null) {
return true;
}
// 检查玩家是否拥有该钥匙
return $this->hasItem($map['key_item']);
}
public function show()
{
Screen::clear($this->game->output);
@ -20,8 +47,18 @@ class DungeonSelectPanel
$out->writeln("");
$maps = require __DIR__ . '/../../src/Data/maps.php';
$availableMaps = [];
// 只显示已解锁的地图
foreach ($maps as $id => $map) {
$out->writeln("[{$id}] {$map['name']} (Lv.{$map['min_level']})");
if ($this->canEnterDungeon($map)) {
$availableMaps[$id] = $map;
$out->writeln("[{$id}] {$map['name']} (Lv.{$map['min_level']})");
} else {
// 显示未解锁的地图
$keyItem = $map['key_item'];
$out->writeln("[\033[90m{$id}\033[0m] {$map['name']} (未解锁 - 需要: {$keyItem})");
}
}
$out->writeln("");
@ -34,12 +71,25 @@ class DungeonSelectPanel
return;
}
if (isset($maps[$dungeonId])) {
$this->game->dungeonId = (int)$dungeonId;
$this->game->state = Game::BATTLE;
} else {
$out->writeln("无效副本");
// 验证选择的副本是否存在
if (!isset($maps[$dungeonId])) {
$out->writeln("\033[91m无效副本\033[0m");
Screen::sleep(1);
return;
}
$selectedMap = $maps[$dungeonId];
// 检查是否有权限进入
if (!$this->canEnterDungeon($selectedMap)) {
$out->writeln("\033[91m该副本尚未解锁\033[0m");
$out->writeln("需要物品: \033[93m{$selectedMap['key_item']}\033[0m");
Screen::sleep(2);
return;
}
// 进入副本
$this->game->dungeonId = (int)$dungeonId;
$this->game->state = Game::BATTLE;
}
}

View File

@ -30,6 +30,7 @@ class InventoryPanel
'necklace' => '项链',
'equipment' => '装备',
'consume' => '消耗品',
'quest_item' => '任务物品',
];
public function __construct(public Game $game) {}
@ -48,7 +49,8 @@ class InventoryPanel
// Filter items by category
if ($category == 'equipment'){
$items = array_values(array_filter($allItems, fn($item) => $item['type'] !== 'consume'));
$items = array_values(array_filter($allItems, fn($item) =>
$item['type'] !== 'consume' && $item['type'] !== 'quest_item'));
}else{
$items = $category === 'all'
? $allItems
@ -157,30 +159,44 @@ class InventoryPanel
$out->writeln("║ 拥有数量: {$quantity}");
}
// 计算售价
$sellPrice = \Game\Entities\Item::calculateSellPrice($item);
$out->writeln("");
$out->writeln("║ 💰 售价: {$sellPrice} 灵石");
// 任务物品不显示售价
if ($item['type'] !== 'quest_item') {
// 计算售价
$sellPrice = \Game\Entities\Item::calculateSellPrice($item);
$out->writeln("");
$out->writeln("║ 💰 售价: {$sellPrice} 灵石");
}
$out->writeln("╚════════════════════════════════════════╝");
$out->writeln("");
$isEquip = in_array($item['type'], ['weapon', 'armor', 'boots', 'ring', 'necklace']);
$isQuestItem = $item['type'] === 'quest_item';
if ($isEquip) {
$out->writeln("[1] 装备");
} elseif ($item['type'] === 'consume') {
$out->writeln("[1] 使用");
if ($isQuestItem) {
// 任务物品无法操作
$out->writeln("这是一个关键任务物品,无法进行任何操作。");
$out->writeln("");
$out->writeln("[0] 返回");
} else {
if ($isEquip) {
$out->writeln("[1] 装备");
} elseif ($item['type'] === 'consume') {
$out->writeln("[1] 使用");
}
$out->writeln("[2] 出售");
$out->writeln("[3] 丢弃");
$out->writeln("[0] 返回");
}
$out->writeln("[2] 出售");
$out->writeln("[3] 丢弃");
$out->writeln("[0] 返回");
$choice = Screen::input($out, "选择操作:");
if ($choice == 1) $this->useItem($item, $inventoryIndex);
if ($choice == 2) $this->sellItem($item, $inventoryIndex);
if ($choice == 3) $this->dropItem($item, $inventoryIndex);
if (!$isQuestItem) {
if ($choice == 1) $this->useItem($item, $inventoryIndex);
if ($choice == 2) $this->sellItem($item, $inventoryIndex);
if ($choice == 3) $this->dropItem($item, $inventoryIndex);
}
return $this->show($page, $category);
}

View File

@ -5,6 +5,7 @@ use Game\Entities\Item;
require __DIR__ . '/../vendor/autoload.php';
$monster = \Game\Entities\Monster::create(6);
dd($monster->getTotalExpForLevel(10) - $monster->getTotalExpForLevel(9));
dd($monster->getRandomEquipmentDrops(100));
//$player = new \Game\Entities\Player();