416 lines
14 KiB
PHP
416 lines
14 KiB
PHP
<?php
|
||
namespace Game\Core;
|
||
|
||
/**
|
||
* 统一的装备显示工具类
|
||
*/
|
||
class ItemDisplay
|
||
{
|
||
// 品质颜色
|
||
private static array $qualityColors = [
|
||
'common' => Colors::WHITE,
|
||
'rare' => Colors::BLUE,
|
||
'epic' => Colors::MAGENTA,
|
||
'legendary' => Colors::YELLOW,
|
||
];
|
||
|
||
// 品质名称
|
||
private static array $qualityNames = [
|
||
'common' => '普通',
|
||
'rare' => '稀有',
|
||
'epic' => '史诗',
|
||
'legendary' => '传说',
|
||
];
|
||
|
||
// 类型名称
|
||
private static array $typeNames = [
|
||
'weapon' => '武器',
|
||
'armor' => '护甲',
|
||
'boots' => '靴子',
|
||
'ring' => '戒指',
|
||
'necklace' => '项链',
|
||
'consume' => '消耗品',
|
||
'spell' => '法术',
|
||
];
|
||
|
||
// 属性名称
|
||
private static array $statNames = [
|
||
'patk' => '物攻',
|
||
'matk' => '魔攻',
|
||
'pdef' => '物防',
|
||
'mdef' => '魔防',
|
||
'hp' => '生命',
|
||
'crit' => '暴击',
|
||
'critdmg' => '暴伤',
|
||
'heal' => '治疗',
|
||
'cost' => '消耗',
|
||
'damage' => '伤害倍率',
|
||
];
|
||
|
||
// 颜色常量
|
||
private static string $reset = Colors::RESET;
|
||
private static string $yellow = Colors::YELLOW;
|
||
private static string $green = Colors::GREEN;
|
||
private static string $cyan = Colors::CYAN;
|
||
private static string $white = Colors::WHITE;
|
||
private static string $gray = Colors::GRAY;
|
||
|
||
/**
|
||
* 获取品质颜色
|
||
*/
|
||
public static function getQualityColor(string $quality): string
|
||
{
|
||
return self::$qualityColors[$quality] ?? self::$white;
|
||
}
|
||
|
||
/**
|
||
* 获取品质名称
|
||
*/
|
||
public static function getQualityName(string $quality): string
|
||
{
|
||
return self::$qualityNames[$quality] ?? '普通';
|
||
}
|
||
|
||
/**
|
||
* 获取类型名称
|
||
*/
|
||
public static function getTypeName(string $type): string
|
||
{
|
||
return self::$typeNames[$type] ?? ucfirst($type);
|
||
}
|
||
|
||
/**
|
||
* 格式化装备名称(带品质颜色和强化等级)
|
||
*/
|
||
public static function formatName(array $item): string
|
||
{
|
||
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
|
||
$color = self::getQualityColor($quality);
|
||
$name = ($item['name'] ?? '未知物品') . 'lv.' . $item['level'];
|
||
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
$enhanceStr = $enhanceLevel > 0 ? self::$yellow . "+{$enhanceLevel}" . self::$reset : "";
|
||
|
||
return $color . $name . self::$reset . $enhanceStr;
|
||
}
|
||
|
||
/**
|
||
* 格式化主属性(单行简洁版)
|
||
*/
|
||
public static function formatStatsCompact(array $item): string
|
||
{
|
||
$stats = [];
|
||
|
||
foreach (self::$statNames as $key => $name) {
|
||
$value = $item[$key] ?? 0;
|
||
if ($value > 0) {
|
||
if ($key === 'damage') {
|
||
$stats[] = "{$name}:{$value}x";
|
||
} else {
|
||
$stats[] = "{$name}+{$value}";
|
||
}
|
||
}
|
||
}
|
||
|
||
return $stats ? self::$green . "(" . implode(" ", $stats) . ")" . self::$reset : "";
|
||
}
|
||
|
||
|
||
/**
|
||
* 格式化主属性(多行详细版)
|
||
*/
|
||
public static function formatStatsDetailed(array $item, string $prefix = " "): array
|
||
{
|
||
$lines = [];
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
|
||
// 法术强化逻辑不同
|
||
$isSpell = ($item['type'] ?? '') === 'spell';
|
||
|
||
if ($isSpell) {
|
||
// 法术强化: 伤害+5%, 消耗-2
|
||
$damageMultiplier = 1 + ($enhanceLevel * 0.05);
|
||
$costReduction = $enhanceLevel * 2;
|
||
|
||
foreach (self::$statNames as $key => $name) {
|
||
$baseValue = $item[$key] ?? 0;
|
||
if ($baseValue > 0) {
|
||
if ($key === 'damage') {
|
||
$finalValue = number_format($baseValue * $damageMultiplier, 2);
|
||
if ($enhanceLevel > 0) {
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$white . $baseValue . "x" . self::$reset . " → " .
|
||
self::$green . $finalValue . "x" . self::$reset;
|
||
} else {
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$green . $baseValue . "x" . self::$reset;
|
||
}
|
||
} elseif ($key === 'cost') {
|
||
$finalValue = max(1, $baseValue - $costReduction);
|
||
if ($enhanceLevel > 0) {
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$white . $baseValue . self::$reset . " → " .
|
||
self::$green . $finalValue . self::$reset;
|
||
} else {
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$green . $baseValue . self::$reset;
|
||
}
|
||
} else {
|
||
// For other stats on spells, just display the base value
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$green . $baseValue . self::$reset;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// 装备强化逻辑
|
||
$enhanceMultiplier = 1 + ($enhanceLevel * 0.05);
|
||
|
||
foreach (self::$statNames as $key => $name) {
|
||
$baseValue = $item[$key] ?? 0;
|
||
if ($baseValue > 0) {
|
||
$finalValue = (int)($baseValue * $enhanceMultiplier);
|
||
if ($enhanceLevel > 0 && $key !== 'heal') {
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$white . $baseValue . self::$reset . " → " .
|
||
self::$green . $finalValue . self::$reset;
|
||
} else {
|
||
$lines[] = $prefix . self::$cyan . $name . self::$reset . ": " .
|
||
self::$green . $baseValue . self::$reset;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return $lines;
|
||
}
|
||
|
||
/**
|
||
* 格式化词条
|
||
*/
|
||
public static function formatAffixes(array $item, string $prefix = " "): array
|
||
{
|
||
$lines = [];
|
||
$affixes = $item['affixes'] ?? [];
|
||
|
||
if (!empty($affixes)) {
|
||
foreach ($affixes as $affix) {
|
||
$lines[] = $prefix . self::$yellow . "◆ " . self::$reset . $affix;
|
||
}
|
||
}
|
||
|
||
return $lines;
|
||
}
|
||
|
||
/**
|
||
* 渲染物品简略信息(用于列表)
|
||
* 格式: [品质色]名称[/品质色]+强化 (类型) 主属性 <词条数>
|
||
* 注:法术显示由 SpellDisplay::formatSpellCompact() 处理
|
||
*/
|
||
public static function renderListItem(array $item, bool $showType = true, bool $showQuantity = true): string
|
||
{
|
||
|
||
// 主属性(简洁版)或法术信息
|
||
$type = $item['type'] ?? '';
|
||
if ($type === 'spell') {
|
||
// 法术显示由 SpellDisplay 处理(计算方式和基础数值)
|
||
// 需要导入 SpellDisplay 后使用
|
||
$statsStr = SpellDisplay::renderListItem($item);
|
||
// 为了向后兼容,使用内联逻辑(调用处应该使用 SpellDisplay)
|
||
} else {
|
||
// 显示装备的属性
|
||
$parts = [];
|
||
|
||
// 名称(带品质颜色和强化)
|
||
$parts[] = self::formatName($item);
|
||
|
||
// 数量
|
||
$quantity = $item['quantity'] ?? 1;
|
||
if ($showQuantity && $quantity > 1) {
|
||
$parts[] = self::$gray . "x{$quantity}" . self::$reset;
|
||
}
|
||
|
||
// 类型
|
||
if ($showType) {
|
||
$type = $item['type'] ?? '';
|
||
$typeName = self::getTypeName($type);
|
||
$parts[] = self::$gray . "[{$typeName}]" . self::$reset;
|
||
}
|
||
$statsStr = self::formatStatsCompact($item);
|
||
|
||
}
|
||
if ($statsStr) {
|
||
$parts[] = $statsStr;
|
||
}
|
||
|
||
// 词条数量提示(仅限装备)
|
||
if ($type !== 'spell') {
|
||
$affixes = $item['affixes'] ?? [];
|
||
if (!empty($affixes)) {
|
||
$count = count($affixes);
|
||
$parts[] = self::$cyan . implode(',',$affixes);
|
||
}
|
||
}
|
||
|
||
return implode(" ", $parts);
|
||
}
|
||
|
||
/**
|
||
* 渲染物品详细信息(用于详情面板)
|
||
* 返回多行数组
|
||
*/
|
||
public static function renderDetail(array $item, string $linePrefix = "║ "): array
|
||
{
|
||
$lines = [];
|
||
|
||
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
|
||
$qualityColor = self::getQualityColor($quality);
|
||
$qualityName = self::getQualityName($quality);
|
||
|
||
$type = $item['type'] ?? '';
|
||
$typeName = self::getTypeName($type);
|
||
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
|
||
// 名称行
|
||
$lines[] = $linePrefix . self::formatName($item);
|
||
$lines[] = $linePrefix;
|
||
|
||
// 品质和类型
|
||
$lines[] = $linePrefix . "品质: " . $qualityColor . $qualityName . self::$reset;
|
||
$lines[] = $linePrefix . "类型: " . self::$white . $typeName . self::$reset;
|
||
|
||
// 强化等级
|
||
if ($enhanceLevel > 0) {
|
||
$bonus = $enhanceLevel * 5;
|
||
$lines[] = $linePrefix . "强化: " . self::$yellow . "+{$enhanceLevel}" . self::$reset .
|
||
self::$gray . " (属性+{$bonus}%)" . self::$reset;
|
||
}
|
||
|
||
$lines[] = $linePrefix;
|
||
|
||
// 法术特殊显示
|
||
if ($type === 'spell') {
|
||
$lines[] = $linePrefix . self::$white . "--- 法术信息 ---" . self::$reset;
|
||
$lines += SpellDisplay::renderDetail($item);
|
||
$lines[] = $linePrefix;
|
||
}else{
|
||
// 主属性
|
||
$lines[] = $linePrefix . self::$white . "--- 主属性 ---" . self::$reset;
|
||
$statLines = self::formatStatsDetailed($item, $linePrefix . " ");
|
||
if (!empty($statLines)) {
|
||
$lines = array_merge($lines, $statLines);
|
||
} else {
|
||
$lines[] = $linePrefix . " " . self::$gray . "(无)" . self::$reset;
|
||
}
|
||
|
||
// 词条
|
||
$affixes = $item['affixes'] ?? [];
|
||
if (!empty($affixes)) {
|
||
$lines[] = $linePrefix;
|
||
$lines[] = $linePrefix . self::$white . "--- 词条 ---" . self::$reset;
|
||
$affixLines = self::formatAffixes($item, $linePrefix . " ");
|
||
$lines = array_merge($lines, $affixLines);
|
||
}
|
||
|
||
// 描述
|
||
$desc = $item['desc'] ?? '';
|
||
if ($desc) {
|
||
$lines[] = $linePrefix;
|
||
$lines[] = $linePrefix . self::$gray . $desc . self::$reset;
|
||
}
|
||
}
|
||
|
||
return $lines;
|
||
}
|
||
|
||
/**
|
||
* 渲染装备槽位信息(用于属性面板)
|
||
* 注:法术显示由 SpellDisplay::renderSlot() 处理
|
||
*/
|
||
public static function renderSlot(string $slotName, ?array $item, string $linePrefix = "║ "): array
|
||
{
|
||
// 委托给 SpellDisplay 处理法术,其他类型则在此处理
|
||
if ($item && ($item['type'] ?? '') === 'spell') {
|
||
// 法术显示由 SpellDisplay 完全处理
|
||
// 调用处应该直接使用 SpellDisplay::renderSlot()
|
||
// 这里为了向后兼容保留了基本支持
|
||
}
|
||
|
||
$lines = [];
|
||
|
||
if ($item) {
|
||
$type = $item['type'] ?? '';
|
||
|
||
// 第一行:槽位名 + 装备/法术名
|
||
$lines[] = $linePrefix . self::$cyan . $slotName . self::$reset . ": " . self::formatName($item);
|
||
|
||
if ($type !== 'spell') {
|
||
// 装备显示:属性和词条
|
||
$statsStr = self::formatStatsCompact($item);
|
||
if ($statsStr) {
|
||
$lines[] = $linePrefix . " " . $statsStr;
|
||
}
|
||
|
||
// 词条
|
||
$affixes = $item['affixes'] ?? [];
|
||
foreach ($affixes as $affix) {
|
||
$lines[] = $linePrefix . " " . self::$yellow . "◆" . self::$reset . " " . $affix;
|
||
}
|
||
}
|
||
} else {
|
||
$lines[] = $linePrefix . self::$cyan . $slotName . self::$reset . ": " .
|
||
self::$gray . "(空)" . self::$reset;
|
||
}
|
||
|
||
return $lines;
|
||
}
|
||
|
||
/**
|
||
* 渲染战斗掉落物品(简洁版)
|
||
*/
|
||
public static function renderDrop(array $item, string $prefix = " "): string
|
||
{
|
||
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
|
||
$color = self::getQualityColor($quality);
|
||
if ($item['type'] == 'potion_pool'){
|
||
return self::$green .$item['name'] . '+' .$item['heal'];
|
||
}
|
||
$name = ($item['name'] ?? '未知物品') . 'lv.' . ($item['level'] ?? '');
|
||
|
||
$enhanceLevel = $item['enhanceLevel'] ?? 0;
|
||
$enhanceStr = $enhanceLevel > 0 ? self::$yellow . "+{$enhanceLevel}" . self::$reset : "";
|
||
|
||
// 简要属性
|
||
$stats = [];
|
||
foreach (['patk', 'matk', 'pdef', 'mdef', 'hp'] as $key) {
|
||
$value = $item[$key] ?? 0;
|
||
if ($value > 0) {
|
||
$statName = self::$statNames[$key] ?? $key;
|
||
$stats[] = "{$statName}+{$value}";
|
||
}
|
||
}
|
||
$statsStr = $stats ? self::$gray . " (" . implode(" ", $stats) . ")" . self::$reset : "";
|
||
|
||
// 词条数量
|
||
$affixCount = count($item['affixes'] ?? []);
|
||
$affixStr = $affixCount > 0 ? self::$cyan . " <{$affixCount}词条>" . self::$reset : "";
|
||
|
||
return $prefix . "✦ " . $color . $name . self::$reset . $enhanceStr . $statsStr . $affixStr;
|
||
}
|
||
|
||
/**
|
||
* 根据品质获取数组索引
|
||
*/
|
||
private static function getQualityIndex(string $quality): int
|
||
{
|
||
return match($quality) {
|
||
'common' => 0,
|
||
'rare' => 1,
|
||
'epic' => 2,
|
||
'legendary' => 3,
|
||
default => 0,
|
||
};
|
||
}
|
||
}
|