新增功能:
- ItemDisplay.renderSlot: 增强支持法术物品显示
- 法术显示计算方式描述
- 法术显示品质相关的基础数值
- 法术显示消耗(含强化后的实际消耗)
- 装备仍显示属性和词条(无改动)
- StatsPanel 导入 SpellDisplay 以支持未来扩展
改进内容:
- 角色面板技能栏显示法术的详细信息
- 显示14种计算方式的完整描述
- 显示伤害倍数或治疗系数(根据品质)
- 显示强化前后的魔法消耗变化
- 保持与战斗系统显示的一致性
显示格式示例:
[技能1] 火球术 Lv.5 +2
计算: 基于魔攻
倍数: 2.0x
消耗: 20 → 16
[技能2] 恢复术 Lv.3
计算: 基于魔攻
治疗: 0.8x + 40
消耗: 15
🧙 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
919 lines
34 KiB
PHP
919 lines
34 KiB
PHP
<?php
|
||
namespace Game\Modules;
|
||
|
||
use Game\Core\Colors;
|
||
use Game\Core\Game;
|
||
use Game\Core\Screen;
|
||
use Game\Core\Input;
|
||
use Game\Core\ItemDisplay;
|
||
use Game\Core\SpellDisplay;
|
||
use Game\Services\EquipmentEnhancer;
|
||
use Game\Entities\Actor;
|
||
use Game\Entities\Partner;
|
||
|
||
class StatsPanel
|
||
{
|
||
// 强化配置
|
||
private array $enhanceConfig = [
|
||
// 等级 => [成功率%, 费用, 失败掉级概率%]
|
||
0 => ['rate' => 100, 'cost' => 50, 'downgrade' => 0],
|
||
1 => ['rate' => 95, 'cost' => 100, 'downgrade' => 0],
|
||
2 => ['rate' => 90, 'cost' => 150, 'downgrade' => 0],
|
||
3 => ['rate' => 85, 'cost' => 200, 'downgrade' => 0],
|
||
4 => ['rate' => 80, 'cost' => 300, 'downgrade' => 10],
|
||
5 => ['rate' => 70, 'cost' => 400, 'downgrade' => 20],
|
||
6 => ['rate' => 60, 'cost' => 500, 'downgrade' => 30],
|
||
7 => ['rate' => 50, 'cost' => 650, 'downgrade' => 40],
|
||
8 => ['rate' => 40, 'cost' => 800, 'downgrade' => 50],
|
||
9 => ['rate' => 30, 'cost' => 1000, 'downgrade' => 60],
|
||
10 => ['rate' => 20, 'cost' => 1500, 'downgrade' => 70],
|
||
11 => ['rate' => 15, 'cost' => 2000, 'downgrade' => 80],
|
||
12 => ['rate' => 10, 'cost' => 3000, 'downgrade' => 90],
|
||
13 => ['rate' => 7, 'cost' => 4000, 'downgrade' => 95],
|
||
14 => ['rate' => 5, 'cost' => 5000, 'downgrade' => 100],
|
||
];
|
||
|
||
// 颜色
|
||
private string $cyan;
|
||
private string $yellow;
|
||
private string $green;
|
||
private string $magenta;
|
||
private string $red;
|
||
private string $white;
|
||
private string $blue;
|
||
private string $reset;
|
||
|
||
// 品质颜色
|
||
private array $qualityColors = [];
|
||
|
||
// 品质名称
|
||
private array $qualityNames = [
|
||
'common' => '普通',
|
||
'rare' => '稀有',
|
||
'epic' => '史诗',
|
||
'legendary' => '传说',
|
||
];
|
||
|
||
// 当前查看的角色
|
||
private ?Actor $currentActor = null;
|
||
private bool $isPlayer = true;
|
||
|
||
public function __construct(public Game $game) {
|
||
$this->cyan = Colors::CYAN;
|
||
$this->yellow = Colors::YELLOW;
|
||
$this->green = Colors::GREEN;
|
||
$this->magenta = Colors::MAGENTA;
|
||
$this->red = Colors::RED;
|
||
$this->white = Colors::WHITE;
|
||
$this->blue = Colors::BLUE;
|
||
$this->reset = Colors::RESET;
|
||
|
||
$this->qualityColors = [
|
||
'common' => Colors::WHITE,
|
||
'rare' => Colors::BLUE,
|
||
'epic' => Colors::MAGENTA,
|
||
'legendary' => Colors::YELLOW,
|
||
];
|
||
}
|
||
|
||
public function show()
|
||
{
|
||
// 默认显示玩家
|
||
$this->currentActor = $this->game->player;
|
||
$this->isPlayer = true;
|
||
|
||
return $this->showCharacterSelect();
|
||
}
|
||
|
||
/**
|
||
* 显示角色选择界面
|
||
*/
|
||
private function showCharacterSelect()
|
||
{
|
||
while (true) {
|
||
Screen::clear($this->game->output);
|
||
$out = $this->game->output;
|
||
|
||
$out->writeln("{$this->cyan}========== 角色管理 =========={$this->reset}");
|
||
$out->writeln("");
|
||
|
||
// 显示玩家
|
||
$playerStats = $this->game->player->getStats();
|
||
$mark = $this->isPlayer && $this->currentActor === $this->game->player ? "{$this->green}►{$this->reset} " : " ";
|
||
$out->writeln("{$mark}[1] {$this->yellow}玩家{$this->reset} Lv.{$this->game->player->level}");
|
||
$out->writeln(" HP:{$playerStats['maxHp']} 物攻:{$playerStats['patk']} 魔攻:{$playerStats['matk']} 暴击:{$playerStats['crit']}%");
|
||
|
||
// 显示队友
|
||
$partners = $this->game->player->partners;
|
||
if (!empty($partners)) {
|
||
$out->writeln("");
|
||
$out->writeln("{$this->white}--- 队友 ---{$this->reset}");
|
||
$idx = 2;
|
||
foreach ($partners as $partner) {
|
||
$stats = $partner->getStats();
|
||
$mark = !$this->isPlayer && $this->currentActor === $partner ? "{$this->green}►{$this->reset} " : " ";
|
||
$out->writeln("{$mark}[{$idx}] {$this->magenta}{$partner->name}{$this->reset} Lv.{$partner->level}");
|
||
$out->writeln(" HP:{$stats['maxHp']} 物攻:{$stats['patk']} 魔攻:{$stats['matk']} 暴击:{$stats['crit']}%");
|
||
$idx++;
|
||
}
|
||
}
|
||
|
||
$out->writeln("");
|
||
$out->writeln("{$this->cyan}=============================={$this->reset}");
|
||
$out->writeln("输入编号查看详情");
|
||
$out->writeln("[1] 查看玩家 | [0] 返回主菜单");
|
||
|
||
$choice = Input::ask($out, "请选择: ");
|
||
|
||
// Handle 'b' for back to menu
|
||
if (strtolower($choice) == 0) {
|
||
$this->game->state = Game::MENU;
|
||
return;
|
||
}
|
||
|
||
$choice = is_numeric($choice) ? (int)$choice : 1;
|
||
|
||
if ($choice === 1) {
|
||
// 选择0总是选择玩家
|
||
$this->currentActor = $this->game->player;
|
||
$this->isPlayer = true;
|
||
return $this->showActorStats();
|
||
} elseif ($choice > 0) {
|
||
// 选择队友
|
||
$partnerList = array_values($partners);
|
||
if (isset($partnerList[$choice - 2])) {
|
||
$this->currentActor = $partnerList[$choice - 2];
|
||
$this->isPlayer = false;
|
||
return $this->showActorStats();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 显示角色详细属性
|
||
*/
|
||
private function showActorStats()
|
||
{
|
||
while (true) {
|
||
Screen::clear($this->game->output);
|
||
$out = $this->game->output;
|
||
|
||
$actor = $this->currentActor;
|
||
$stats = $actor->getStats();
|
||
|
||
$name = $this->isPlayer ? "玩家" : $actor->name;
|
||
$nameColor = $this->isPlayer ? $this->yellow : $this->magenta;
|
||
|
||
$out->writeln("╔════════════════════════════════════╗");
|
||
$out->writeln("║ {$this->cyan}角色属性面板{$this->reset} ║");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
|
||
$out->writeln("║ 名称: {$nameColor}{$name}{$this->reset}");
|
||
$out->writeln("║ 等级: {$actor->level} (XP: {$actor->exp}/{$actor->maxExp})");
|
||
|
||
if ($this->isPlayer) {
|
||
$out->writeln("║ 💰灵石: {$this->green}{$this->game->player->spiritStones}{$this->reset}");
|
||
}
|
||
|
||
$out->writeln("║ HP: {$this->red}{$stats['hp']}{$this->reset}/{$stats['maxHp']}");
|
||
$out->writeln("║ 物攻: {$this->yellow}{$stats['patk']}{$this->reset}");
|
||
$out->writeln("║ 魔攻: {$this->blue}{$stats['matk']}{$this->reset}");
|
||
$out->writeln("║ 物防: {$this->yellow}{$stats['pdef']}{$this->reset}");
|
||
$out->writeln("║ 魔防: {$this->blue}{$stats['mdef']}{$this->reset}");
|
||
$out->writeln("║ 暴击: {$stats['crit']} %");
|
||
$out->writeln("║ 爆伤: {$stats['critdmg']} %");
|
||
|
||
// 显示天赋信息
|
||
if (!$this->isPlayer) {
|
||
$out->writeln("║");
|
||
$out->writeln("║ {$this->white}天赋(自动分配){$this->reset}");
|
||
$talentNames = ['hp' => '生命', 'patk' => '物攻', 'matk' => '魔攻', 'pdef' => '物防', 'mdef' => '魔防', 'crit' => '暴击', 'critdmg' => '暴伤'];
|
||
$talentParts = [];
|
||
foreach ($talentNames as $key => $tname) {
|
||
if (isset($actor->talents[$key]) && $actor->talents[$key] > 0) {
|
||
$talentParts[] = "{$tname}:{$actor->talents[$key]}";
|
||
}
|
||
}
|
||
if (!empty($talentParts)) {
|
||
$talentStr = implode(" ", $talentParts);
|
||
$out->writeln("║ {$talentStr}");
|
||
}
|
||
}
|
||
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
$out->writeln("║ {$this->magenta}装备栏{$this->reset}");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
|
||
$slotIndex = 1;
|
||
$slots = ['weapon', 'armor', 'boots', 'ring', 'necklace'];
|
||
$slotNames = [
|
||
'weapon' => '武器',
|
||
'armor' => '护甲',
|
||
'boots' => '鞋子',
|
||
'ring' => '戒指',
|
||
'necklace' => '项链',
|
||
];
|
||
|
||
foreach ($slots as $slot) {
|
||
$item = $actor->equip[$slot] ?? null;
|
||
$slotName = $slotNames[$slot];
|
||
|
||
if ($item) {
|
||
$slotLines = ItemDisplay::renderSlot($slotName, $item, "║ [{$slotIndex}] ");
|
||
foreach ($slotLines as $i => $line) {
|
||
if ($i === 0) {
|
||
$out->writeln($line);
|
||
} else {
|
||
$out->writeln("║ " . substr($line, 6)); // 缩进对齐
|
||
}
|
||
}
|
||
} else {
|
||
$out->writeln("║ [{$slotIndex}] {$this->cyan}{$slotName}{$this->reset}: " .
|
||
Colors::GRAY . '(空)' . Colors::RESET);
|
||
}
|
||
$slotIndex++;
|
||
}
|
||
|
||
$out->writeln("╚════════════════════════════════════╝");
|
||
$out->writeln("");
|
||
|
||
// 显示技能槽位
|
||
$out->writeln("╔════════════════════════════════════╗");
|
||
$out->writeln("║ {$this->magenta}技能栏{$this->reset}");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
|
||
$skillSlots = ['skill1', 'skill2', 'skill3', 'skill4'];
|
||
$skillIndex = 1;
|
||
foreach ($skillSlots as $slot) {
|
||
$spell = $actor->skillSlots[$slot] ?? null;
|
||
if ($spell) {
|
||
$slotLines = ItemDisplay::renderSlot("技能{$skillIndex}", $spell, "║ [{$skillIndex}] ");
|
||
foreach ($slotLines as $i => $line) {
|
||
if ($i === 0) {
|
||
$out->writeln($line);
|
||
} else {
|
||
$out->writeln("║ " . substr($line, 6));
|
||
}
|
||
}
|
||
} else {
|
||
$out->writeln("║ [{$skillIndex}] {$this->cyan}技能{$skillIndex}{$this->reset}: " . Colors::GRAY . '(空)' . Colors::RESET);
|
||
}
|
||
$skillIndex++;
|
||
}
|
||
$out->writeln("╚════════════════════════════════════╝");
|
||
$out->writeln("");
|
||
|
||
// 显示操作选项 - 统一玩家和队友的操作
|
||
$out->writeln("[1] 装备物品 | [2] 卸下装备 | [3] 强化装备");
|
||
$out->writeln("[5] 装备技能 | [6] 卸下技能 | [7] 强化技能");
|
||
|
||
if ($this->isPlayer) {
|
||
$out->writeln("[s] 切换角色 | [0] 返回");
|
||
} else {
|
||
$out->writeln("[4] {$this->red}解散队友{$this->reset} | [s] 切换角色 | [0] 返回");
|
||
}
|
||
|
||
$choice = Screen::input($out, "选择操作:");
|
||
|
||
if ($choice == 0 || strtolower($choice) === 's') {
|
||
return $this->showCharacterSelect();
|
||
}
|
||
|
||
// 统一处理操作
|
||
switch ($choice) {
|
||
case '1':
|
||
$this->equipItem($actor);
|
||
break;
|
||
case '2':
|
||
$this->unequipItem($actor);
|
||
break;
|
||
case '3':
|
||
$this->enhanceEquipment($actor);
|
||
break;
|
||
case '4':
|
||
if (!$this->isPlayer) {
|
||
$this->dismissPartner($actor);
|
||
return $this->showCharacterSelect(); // 解散后返回选择界面
|
||
}
|
||
break;
|
||
case '5':
|
||
$this->equipSkill($actor);
|
||
break;
|
||
case '6':
|
||
$this->unequipSkill($actor);
|
||
break;
|
||
case '7':
|
||
$this->enhanceSkill($actor);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 为角色装备物品(统一处理玩家和队友)
|
||
*/
|
||
private function equipItem(Actor $actor)
|
||
{
|
||
Screen::clear($this->game->output);
|
||
$this->game->output->writeln("{$this->cyan}========== 装备物品 =========={$this->reset}");
|
||
|
||
// 筛选可装备物品
|
||
$equipableItems = [];
|
||
foreach ($this->game->player->inventory as $idx => $item) {
|
||
$type = $item['type'] ?? '';
|
||
if (in_array($type, ['weapon', 'armor', 'ring', 'boots', 'necklace'])) {
|
||
$equipableItems[$idx] = $item;
|
||
}
|
||
}
|
||
|
||
if (empty($equipableItems)) {
|
||
$this->game->output->writeln("{$this->white}没有可装备的物品{$this->reset}");
|
||
Screen::pause($this->game->output);
|
||
return;
|
||
}
|
||
|
||
$displayIdx = 1;
|
||
$idxMap = [];
|
||
foreach ($equipableItems as $realIdx => $item) {
|
||
$displayStr = ItemDisplay::renderListItem($item, true, false);
|
||
$this->game->output->writeln("[{$displayIdx}] {$displayStr}");
|
||
$idxMap[$displayIdx] = $realIdx;
|
||
$displayIdx++;
|
||
}
|
||
|
||
$this->game->output->writeln("[0] 取消");
|
||
|
||
$choice = Input::ask($this->game->output, "选择装备: ");
|
||
|
||
if ($choice == 0) return;
|
||
|
||
if (!isset($idxMap[$choice])) {
|
||
$this->game->output->writeln("无效选择");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
$realIdx = $idxMap[$choice];
|
||
$item = $this->game->player->inventory[$realIdx];
|
||
$slot = $item['type'];
|
||
|
||
// 如果该槽位已有装备,先卸下
|
||
if (!empty($actor->equip[$slot])) {
|
||
$oldItem = $actor->equip[$slot];
|
||
$this->game->player->addItem($oldItem);
|
||
}
|
||
|
||
// 装备新物品
|
||
$actor->equip[$slot] = $item;
|
||
|
||
// 从背包移除
|
||
unset($this->game->player->inventory[$realIdx]);
|
||
$this->game->player->inventory = array_values($this->game->player->inventory);
|
||
|
||
$this->game->saveState();
|
||
$this->game->output->writeln("{$this->green}已装备 {$item['name']}!{$this->reset}");
|
||
Screen::pause($this->game->output);
|
||
}
|
||
|
||
/**
|
||
* 为角色卸下装备(统一处理玩家和队友)
|
||
*/
|
||
private function unequipItem(Actor $actor)
|
||
{
|
||
Screen::clear($this->game->output);
|
||
$this->game->output->writeln("{$this->cyan}========== 卸下装备 =========={$this->reset}");
|
||
|
||
$slots = ['weapon' => '武器', 'armor' => '护甲', 'ring' => '戒指', 'boots' => '靴子', 'necklace' => '项链'];
|
||
$equipped = [];
|
||
$idx = 1;
|
||
|
||
foreach ($slots as $slot => $name) {
|
||
if (!empty($actor->equip[$slot])) {
|
||
$item = $actor->equip[$slot];
|
||
$this->game->output->writeln("[{$idx}] {$name}: " . ItemDisplay::formatName($item));
|
||
$equipped[$idx] = $slot;
|
||
$idx++;
|
||
}
|
||
}
|
||
|
||
if (empty($equipped)) {
|
||
$this->game->output->writeln("{$this->white}没有已装备的物品{$this->reset}");
|
||
Screen::pause($this->game->output);
|
||
return;
|
||
}
|
||
|
||
$this->game->output->writeln("[0] 取消");
|
||
|
||
$choice = Input::ask($this->game->output, "选择卸下: ");
|
||
|
||
if ($choice == 0) return;
|
||
|
||
if (!isset($equipped[$choice])) {
|
||
$this->game->output->writeln("无效选择");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
$slot = $equipped[$choice];
|
||
$item = $actor->equip[$slot];
|
||
|
||
// 放回背包
|
||
$this->game->player->addItem($item);
|
||
$actor->equip[$slot] = null;
|
||
|
||
$this->game->saveState();
|
||
$this->game->output->writeln("{$this->green}已卸下 {$item['name']}!{$this->reset}");
|
||
Screen::pause($this->game->output);
|
||
}
|
||
|
||
/**
|
||
* 解散队友
|
||
*/
|
||
private function dismissPartner(Partner $partner): bool
|
||
{
|
||
$this->game->output->writeln("");
|
||
$this->game->output->writeln("{$this->red}确定要解散 {$partner->name} 吗?{$this->reset}");
|
||
$this->game->output->writeln("{$this->white}解散后装备将返还背包{$this->reset}");
|
||
|
||
$confirm = Input::ask($this->game->output, "确认解散?[y/n]: ");
|
||
|
||
if (strtolower($confirm) !== 'y') {
|
||
$this->game->output->writeln("取消解散");
|
||
Screen::sleep(1);
|
||
return false;
|
||
}
|
||
|
||
// 返还装备
|
||
foreach ($partner->equip as $item) {
|
||
if (!empty($item)) {
|
||
$this->game->player->addItem($item);
|
||
}
|
||
}
|
||
|
||
// 解散同伴
|
||
$this->game->player->dismissPartner($partner->id);
|
||
$this->game->saveState();
|
||
|
||
$this->game->output->writeln("{$this->yellow}{$partner->name} 离开了队伍{$this->reset}");
|
||
Screen::pause($this->game->output);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 为角色强化装备(统一处理玩家和队友)
|
||
*/
|
||
private function enhanceEquipment(Actor $actor)
|
||
{
|
||
Screen::clear($this->game->output);
|
||
$this->game->output->writeln("{$this->cyan}========== 装备强化 =========={$this->reset}");
|
||
|
||
$slots = ['weapon' => '武器', 'armor' => '护甲', 'ring' => '戒指', 'boots' => '靴子', 'necklace' => '项链'];
|
||
$equipped = [];
|
||
$idx = 1;
|
||
|
||
foreach ($slots as $slot => $name) {
|
||
if (!empty($actor->equip[$slot])) {
|
||
$item = $actor->equip[$slot];
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
$this->game->output->writeln("[{$idx}] {$name}: " . ItemDisplay::formatName($item) . " {$this->yellow}+{$enhanceLevel}{$this->reset}");
|
||
$equipped[$idx] = $slot;
|
||
$idx++;
|
||
}
|
||
}
|
||
|
||
if (empty($equipped)) {
|
||
$this->game->output->writeln("{$this->white}没有已装备的物品{$this->reset}");
|
||
Screen::pause($this->game->output);
|
||
return;
|
||
}
|
||
|
||
$this->game->output->writeln("[0] 取消");
|
||
|
||
$choice = Input::ask($this->game->output, "选择要强化的装备: ");
|
||
|
||
if ($choice == 0) return;
|
||
|
||
if (!isset($equipped[$choice])) {
|
||
$this->game->output->writeln("无效选择");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
$slot = $equipped[$choice];
|
||
$this->showEnhancePanel($slot, $actor);
|
||
}
|
||
|
||
private function showEnhancePanel(string $slot, Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
|
||
$item = $actor->equip[$slot] ?? null;
|
||
|
||
if (!$item) {
|
||
$out->writeln("该位置没有装备!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
Screen::clear($out);
|
||
|
||
$slotName = match ($slot) {
|
||
"weapon" => "武器",
|
||
"armor" => "护甲",
|
||
"boots" => "鞋子",
|
||
"ring" => "戒指",
|
||
"necklace" => "项链",
|
||
default => ucfirst($slot)
|
||
};
|
||
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
$maxLevel = 15;
|
||
|
||
if ($enhanceLevel >= $maxLevel) {
|
||
$out->writeln("该装备已达到最高强化等级!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
$config = $this->enhanceConfig[$enhanceLevel] ?? $this->enhanceConfig[14];
|
||
$successRate = $config['rate'];
|
||
$cost = $config['cost'];
|
||
$downgradeChance = $config['downgrade'];
|
||
|
||
// 计算强化后的属性预览
|
||
$currentBonus = $this->calculateEnhanceBonus($enhanceLevel);
|
||
$nextBonus = $this->calculateEnhanceBonus($enhanceLevel + 1);
|
||
|
||
// 获取品质
|
||
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
|
||
|
||
$out->writeln("╔════════════════════════════════════╗");
|
||
$out->writeln("║ {$this->cyan}装备强化{$this->reset} ║");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
|
||
// 使用统一的装备显示
|
||
$out->writeln("║ 位置: {$slotName}");
|
||
$out->writeln("║ 装备: " . ItemDisplay::formatName($item));
|
||
$out->writeln("║ 品质: " . ItemDisplay::getQualityColor($quality) .
|
||
ItemDisplay::getQualityName($quality) . $this->reset);
|
||
$out->writeln("║");
|
||
|
||
// 显示主属性
|
||
$out->writeln("║ {$this->white}--- 主属性 ---{$this->reset}");
|
||
$statLines = ItemDisplay::formatStatsDetailed($item, "║ ");
|
||
foreach ($statLines as $line) {
|
||
$out->writeln($line);
|
||
}
|
||
|
||
// 显示词条
|
||
$affixes = $item['affixes'] ?? [];
|
||
if (!empty($affixes)) {
|
||
$out->writeln("║");
|
||
$out->writeln("║ {$this->white}--- 词条 ---{$this->reset}");
|
||
$affixLines = ItemDisplay::formatAffixes($item, "║ ");
|
||
foreach ($affixLines as $line) {
|
||
$out->writeln($line);
|
||
}
|
||
}
|
||
|
||
$out->writeln("║");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
$out->writeln("║");
|
||
$out->writeln("║ 当前强化等级: {$this->green}+{$enhanceLevel}{$this->reset}");
|
||
$out->writeln("║ 当前属性加成: {$this->green}+{$currentBonus}%{$this->reset}");
|
||
$out->writeln("║");
|
||
$out->writeln("║ ➜ 强化至 {$this->yellow}+".($enhanceLevel + 1)."{$this->reset}");
|
||
$out->writeln("║ 属性加成: {$this->yellow}+{$nextBonus}%{$this->reset}");
|
||
$out->writeln("║");
|
||
$out->writeln("║ 成功率: {$this->green}{$successRate}%{$this->reset}");
|
||
if ($downgradeChance > 0) {
|
||
$out->writeln("║ 失败掉级概率: {$this->red}{$downgradeChance}%{$this->reset}");
|
||
}
|
||
$out->writeln("║ 费用: {$this->yellow}{$cost}{$this->reset} 灵石");
|
||
$out->writeln("║");
|
||
$out->writeln("║ 你的灵石: {$this->green}{$this->game->player->spiritStones}{$this->reset}");
|
||
$out->writeln("╚════════════════════════════════════╝");
|
||
$out->writeln("");
|
||
$out->writeln("[1] 强化 | [0] 返回");
|
||
|
||
$choice = Screen::input($out, "选择操作:");
|
||
|
||
if ($choice == 1) {
|
||
$this->doEnhance($slot, $actor);
|
||
}
|
||
}
|
||
|
||
private function doEnhance(string $slot, Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
|
||
$item = &$actor->equip[$slot];
|
||
if (!$item) return;
|
||
|
||
// 使用 EquipmentEnhancer 模块执行强化
|
||
$result = EquipmentEnhancer::enhance($item, $this->game->player);
|
||
|
||
// 显示强化结果
|
||
$out->writeln("");
|
||
|
||
if ($result['success']) {
|
||
// 强化成功
|
||
$out->writeln("{$this->green}★ 强化成功!{$this->reset}");
|
||
$out->writeln("装备强化等级提升至 {$this->yellow}+{$result['newLevel']}{$this->reset}");
|
||
} else {
|
||
// 强化失败或其他原因
|
||
if ($result['cost'] === 0) {
|
||
// 灵石不足或已达最大等级
|
||
$out->writeln("{$this->red}✗ {$result['message']}{$this->reset}");
|
||
} else {
|
||
// 强化失败
|
||
$out->writeln("{$this->red}✗ 强化失败!{$this->reset}");
|
||
if ($result['downgraded']) {
|
||
$out->writeln("{$this->red}装备强化等级下降至 +{$result['newLevel']}{$this->reset}");
|
||
} else {
|
||
$out->writeln("强化等级保持不变");
|
||
}
|
||
}
|
||
}
|
||
|
||
$this->game->saveState();
|
||
Screen::sleep(1);
|
||
}
|
||
|
||
/**
|
||
* 计算强化等级对应的属性加成百分比
|
||
*/
|
||
private function calculateEnhanceBonus(int $level): int
|
||
{
|
||
// 每级增加 5% 属性加成
|
||
return $level * 5;
|
||
}
|
||
|
||
/**
|
||
* 装备技能
|
||
*/
|
||
private function equipSkill(Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
Screen::clear($out);
|
||
|
||
// 1. 获取背包中的法术
|
||
$spells = [];
|
||
foreach ($this->game->player->inventory as $index => $item) {
|
||
if (($item['type'] ?? '') === 'spell') {
|
||
$spells[$index] = $item;
|
||
}
|
||
}
|
||
|
||
if (empty($spells)) {
|
||
$out->writeln("背包中没有法术!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
// 2. 显示法术列表
|
||
$out->writeln("{$this->cyan}选择要装备的法术:{$this->reset}");
|
||
$spellIndices = [];
|
||
$i = 1;
|
||
foreach ($spells as $index => $item) {
|
||
$out->writeln("[{$i}] " . ItemDisplay::renderListItem($item));
|
||
$spellIndices[$i] = $index;
|
||
$i++;
|
||
}
|
||
$out->writeln("[0] 返回");
|
||
|
||
$choice = Screen::input($out, "请选择: ");
|
||
if ($choice == 0 || !isset($spellIndices[$choice])) return;
|
||
|
||
$inventoryIndex = $spellIndices[$choice];
|
||
$selectedSpell = $spells[$inventoryIndex];
|
||
|
||
// 3. 选择技能槽位
|
||
Screen::clear($out);
|
||
$out->writeln("{$this->cyan}选择技能槽位:{$this->reset}");
|
||
$skillSlots = ['skill1', 'skill2', 'skill3', 'skill4'];
|
||
$i = 1;
|
||
foreach ($skillSlots as $slot) {
|
||
$currentSpell = $actor->skillSlots[$slot] ?? null;
|
||
if ($currentSpell) {
|
||
$out->writeln("[{$i}] 技能{$i}: " . ItemDisplay::formatName($currentSpell));
|
||
} else {
|
||
$out->writeln("[{$i}] 技能{$i}: (空)");
|
||
}
|
||
$i++;
|
||
}
|
||
$out->writeln("[0] 返回");
|
||
|
||
$slotChoice = Screen::input($out, "请选择槽位: ");
|
||
if ($slotChoice < 1 || $slotChoice > 4) return;
|
||
|
||
$targetSlot = $skillSlots[$slotChoice - 1];
|
||
|
||
// 4. 执行装备
|
||
// 如果槽位已有技能,先卸下
|
||
if (isset($actor->skillSlots[$targetSlot])) {
|
||
$this->game->player->addItem($actor->skillSlots[$targetSlot]);
|
||
}
|
||
|
||
// 装备新技能
|
||
$actor->skillSlots[$targetSlot] = $selectedSpell;
|
||
|
||
// 从背包移除
|
||
unset($this->game->player->inventory[$inventoryIndex]);
|
||
$this->game->player->inventory = array_values($this->game->player->inventory);
|
||
|
||
$out->writeln("{$this->green}装备成功!{$this->reset}");
|
||
$this->game->saveState();
|
||
Screen::sleep(1);
|
||
}
|
||
|
||
/**
|
||
* 卸下技能
|
||
*/
|
||
private function unequipSkill(Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
Screen::clear($out);
|
||
|
||
$out->writeln("{$this->cyan}选择要卸下的技能:{$this->reset}");
|
||
$skillSlots = ['skill1', 'skill2', 'skill3', 'skill4'];
|
||
$hasSkill = false;
|
||
$i = 1;
|
||
foreach ($skillSlots as $slot) {
|
||
$currentSpell = $actor->skillSlots[$slot] ?? null;
|
||
if ($currentSpell) {
|
||
$out->writeln("[{$i}] 技能{$i}: " . ItemDisplay::formatName($currentSpell));
|
||
$hasSkill = true;
|
||
} else {
|
||
$out->writeln("[{$i}] 技能{$i}: (空)");
|
||
}
|
||
$i++;
|
||
}
|
||
$out->writeln("[0] 返回");
|
||
|
||
if (!$hasSkill) {
|
||
$out->writeln("没有装备任何技能!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
$slotChoice = Screen::input($out, "请选择槽位: ");
|
||
if ($slotChoice < 1 || $slotChoice > 4) return;
|
||
|
||
$targetSlot = $skillSlots[$slotChoice - 1];
|
||
$spell = $actor->skillSlots[$targetSlot] ?? null;
|
||
|
||
if (!$spell) {
|
||
$out->writeln("该槽位没有技能!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
// 卸下到背包
|
||
$this->game->player->addItem($spell);
|
||
$actor->skillSlots[$targetSlot] = null;
|
||
|
||
$out->writeln("{$this->green}卸下成功!{$this->reset}");
|
||
$this->game->saveState();
|
||
Screen::sleep(1);
|
||
}
|
||
|
||
/**
|
||
* 强化技能
|
||
*/
|
||
private function enhanceSkill(Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
Screen::clear($out);
|
||
|
||
$out->writeln("{$this->cyan}选择要强化的技能:{$this->reset}");
|
||
$skillSlots = ['skill1', 'skill2', 'skill3', 'skill4'];
|
||
$equipped = [];
|
||
$hasSkill = false;
|
||
$i = 1;
|
||
foreach ($skillSlots as $slot) {
|
||
$spell = $actor->skillSlots[$slot] ?? null;
|
||
if ($spell) {
|
||
$out->writeln("[{$i}] 技能{$i}: " . ItemDisplay::formatName($spell));
|
||
$equipped[$i] = $slot;
|
||
$hasSkill = true;
|
||
} else {
|
||
$out->writeln("[{$i}] 技能{$i}: (空)");
|
||
}
|
||
$i++;
|
||
}
|
||
$out->writeln("[0] 返回");
|
||
|
||
if (!$hasSkill) {
|
||
$out->writeln("没有装备任何技能!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
$choice = Screen::input($out, "请选择: ");
|
||
if ($choice == 0 || !isset($equipped[$choice])) return;
|
||
|
||
$slot = $equipped[$choice];
|
||
|
||
// 复用 showEnhancePanel,但需要修改 doEnhance 支持技能
|
||
// 为了简单,我们创建一个专门的 showSkillEnhancePanel
|
||
$this->showSkillEnhancePanel($slot, $actor);
|
||
}
|
||
|
||
private function showSkillEnhancePanel(string $slot, Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
$item = $actor->skillSlots[$slot] ?? null;
|
||
|
||
if (!$item) return;
|
||
|
||
Screen::clear($out);
|
||
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
$maxLevel = 15;
|
||
|
||
if ($enhanceLevel >= $maxLevel) {
|
||
$out->writeln("该技能已达到最高强化等级!");
|
||
Screen::sleep(1);
|
||
return;
|
||
}
|
||
|
||
// 使用与装备相同的强化配置
|
||
$config = $this->enhanceConfig[$enhanceLevel] ?? $this->enhanceConfig[14];
|
||
$successRate = $config['rate'];
|
||
$cost = $config['cost'];
|
||
$downgradeChance = $config['downgrade'];
|
||
|
||
$out->writeln("╔════════════════════════════════════╗");
|
||
$out->writeln("║ {$this->cyan}技能强化{$this->reset} ║");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
$out->writeln("║ 技能: " . ItemDisplay::formatName($item));
|
||
$out->writeln("║");
|
||
|
||
// 显示属性变化
|
||
$out->writeln("║ {$this->white}--- 属性预览 ---{$this->reset}");
|
||
$statLines = ItemDisplay::formatStatsDetailed($item, "║ ");
|
||
foreach ($statLines as $line) {
|
||
$out->writeln($line);
|
||
}
|
||
|
||
$out->writeln("║");
|
||
$out->writeln("╠════════════════════════════════════╣");
|
||
$out->writeln("║");
|
||
$out->writeln("║ 当前等级: {$this->green}+{$enhanceLevel}{$this->reset}");
|
||
$out->writeln("║");
|
||
$out->writeln("║ ➜ 强化至 {$this->yellow}+".($enhanceLevel + 1)."{$this->reset}");
|
||
$out->writeln("║");
|
||
$out->writeln("║ 成功率: {$this->green}{$successRate}%{$this->reset}");
|
||
if ($downgradeChance > 0) {
|
||
$out->writeln("║ 失败掉级概率: {$this->red}{$downgradeChance}%{$this->reset}");
|
||
}
|
||
$out->writeln("║ 费用: {$this->yellow}{$cost}{$this->reset} 灵石");
|
||
$out->writeln("║");
|
||
$out->writeln("║ 你的灵石: {$this->green}{$this->game->player->spiritStones}{$this->reset}");
|
||
$out->writeln("╚════════════════════════════════════╝");
|
||
$out->writeln("");
|
||
$out->writeln("[1] 强化 | [0] 返回");
|
||
|
||
$choice = Screen::input($out, "选择操作:");
|
||
|
||
if ($choice == 1) {
|
||
$this->doEnhanceSkill($slot, $actor);
|
||
}
|
||
}
|
||
|
||
private function doEnhanceSkill(string $slot, Actor $actor)
|
||
{
|
||
$out = $this->game->output;
|
||
$item = &$actor->skillSlots[$slot];
|
||
|
||
if (!$item) return;
|
||
|
||
// 使用 EquipmentEnhancer 模块执行强化 (它应该能处理任何带有 enhanceLevel 的物品)
|
||
// 注意: EquipmentEnhancer 可能需要 Item 对象或数组,这里我们传递的是数组引用
|
||
$result = EquipmentEnhancer::enhance($item, $this->game->player);
|
||
|
||
$out->writeln("");
|
||
|
||
if ($result['success']) {
|
||
$out->writeln("{$this->green}★ 强化成功!{$this->reset}");
|
||
$out->writeln("技能强化等级提升至 {$this->yellow}+{$result['newLevel']}{$this->reset}");
|
||
} else {
|
||
if ($result['cost'] === 0) {
|
||
$out->writeln("{$this->red}✗ {$result['message']}{$this->reset}");
|
||
} else {
|
||
$out->writeln("{$this->red}✗ 强化失败!{$this->reset}");
|
||
if ($result['downgraded']) {
|
||
$out->writeln("{$this->red}技能强化等级下降至 +{$result['newLevel']}{$this->reset}");
|
||
} else {
|
||
$out->writeln("强化等级保持不变");
|
||
}
|
||
}
|
||
}
|
||
|
||
$this->game->saveState();
|
||
Screen::sleep(1);
|
||
}
|
||
}
|