hanli/src/Modules/SpellPanel.php
2025-12-03 18:15:54 +08:00

471 lines
17 KiB
PHP

<?php
namespace Game\Modules;
use Game\Core\Colors;
use Game\Core\Game;
use Game\Core\Input;
use Game\Core\Screen;
class SpellPanel
{
private string $cyan;
private string $white;
private string $reset;
private string $bold;
private string $green;
private string $yellow;
private string $magenta;
private string $red;
public function __construct(public Game $game)
{
$this->cyan = Colors::CYAN;
$this->white = Colors::WHITE;
$this->reset = Colors::RESET;
$this->bold = Colors::BOLD;
$this->green = Colors::GREEN;
$this->yellow = Colors::YELLOW;
$this->magenta = Colors::MAGENTA;
$this->red = Colors::RED;
}
public function show()
{
static $spellsData = null;
if ($spellsData === null) {
$spellsData = require __DIR__ . '/../../src/Data/spells.php';
}
$out = $this->game->output;
$in = $this->game->input;
$player = $this->game->player;
while (true) {
// 清屏显示菜单
Screen::clear($out);
$out->writeln("{$this->bold}{$this->cyan}=== 法术系统 ==={$this->reset}");
$out->writeln("");
// 显示魔法值状态
$manaPercent = ($player->mana / $player->maxMana) * 100;
$manaBar = $this->getManaBar($player->mana, $player->maxMana);
$out->writeln("魔法值: {$manaBar} {$player->mana}/{$player->maxMana}");
$out->writeln("");
// 显示已学习的法术
$out->writeln("{$this->bold}{$this->yellow}已学习的法术:{$this->reset}");
if (empty($player->spells)) {
$out->writeln(" {$this->white}暂无法术{$this->reset}");
} else {
$spellIndex = 0;
foreach ($player->spells as $spellId => $spellData) {
$spellIndex++;
// 获取法术信息
$spellInfo = $this->getSpellInfo($spellId, $spellsData);
$level = $spellData['level'] ?? 1;
$name = $spellInfo['name'] ?? '未知法术';
$quality = $spellInfo['quality'] ?? 'common';
$qualityColor = $this->getQualityColor($quality);
$out->writeln(" [{$spellIndex}] {$qualityColor}{$name}{$this->reset} (Lv.{$level})");
}
}
$out->writeln("");
// 显示拥有的资源书
$out->writeln("{$this->bold}{$this->magenta}拥有的法术资源书:{$this->reset}");
if (empty($player->spellBooks)) {
$out->writeln(" {$this->white}暂无资源书{$this->reset}");
} else {
$bookIndex = 0;
foreach ($player->spellBooks as $spellId => $count) {
$bookIndex++;
$spellInfo = $this->getSpellInfo($spellId, $spellsData);
$name = $spellInfo['name'] ?? '未知法术';
$quality = $spellInfo['quality'] ?? 'common';
$qualityColor = $this->getQualityColor($quality);
$out->writeln(" [{$bookIndex}] {$qualityColor}{$name}的法术书{$this->reset} x{$count}");
}
}
$out->writeln("");
// 菜单选项
$out->writeln("{$this->bold}选择操作:{$this->reset}");
$out->writeln("[1] 查看法术详情");
$out->writeln("[2] 学习法术");
$out->writeln("[3] 升级法术");
$out->writeln("[0] 返回");
$choice = Input::ask($this->game->output, "请选择: ");;
switch ($choice) {
case '1':
$this->viewSpellDetails($spellsData);
break;
case '2':
$this->learnSpell($spellsData);
break;
case '3':
$this->upgradeSpell($spellsData);
break;
case '0':
$this->game->state = Game::MENU;
return;
default:
$out->writeln("{$this->red}无效选择{$this->reset}");
Screen::delay(500000);
}
}
}
/**
* 查看法术详情
*/
private function viewSpellDetails(array $spellsData)
{
$out = $this->game->output;
$player = $this->game->player;
while (true) {
Screen::clear($out);
$out->writeln("{$this->bold}{$this->cyan}=== 法术详情 ==={$this->reset}");
$out->writeln("");
if (empty($player->spells)) {
$out->writeln("{$this->red}还未学习任何法术{$this->reset}");
Screen::delay(1000000);
return;
}
// 列出已学习的法术
$spellArray = [];
$spellIndex = 0;
foreach ($player->spells as $spellId => $spellData) {
$spellIndex++;
$spellInfo = $this->getSpellInfo($spellId, $spellsData);
$name = $spellInfo['name'] ?? '未知法术';
$quality = $spellInfo['quality'] ?? 'common';
$qualityColor = $this->getQualityColor($quality);
$level = $spellData['level'] ?? 1;
$out->writeln("[{$spellIndex}] {$qualityColor}{$name}{$this->reset} (Lv.{$level})");
$spellArray[$spellIndex] = ['spellId' => $spellId, 'spellInfo' => $spellInfo];
}
$out->writeln("[0] 返回");
$choice = Input::ask($this->game->output, "请选择: ");;
if ($choice == '0') {
return;
}
if (isset($spellArray[$choice])) {
$selected = $spellArray[$choice];
$this->displaySpellDetail($selected['spellId'], $selected['spellInfo'], $spellsData);
} else {
$out->writeln("{$this->red}无效选择{$this->reset}");
Screen::delay(500000);
}
}
}
/**
* 显示单个法术的详细信息
*/
private function displaySpellDetail(int $spellId, array $spellInfo, array $spellsData)
{
$out = $this->game->output;
$player = $this->game->player;
Screen::clear($out);
$out->writeln("{$this->bold}{$this->cyan}=== {$spellInfo['name']} ==={$this->reset}");
$out->writeln("");
$quality = $spellInfo['quality'] ?? 'common';
$qualityColor = $this->getQualityColor($quality);
$level = $player->getSpellLevel($spellId);
$out->writeln("品质: {$qualityColor}{$this->getQualityName($quality)}{$this->reset}");
$out->writeln("等级: {$this->yellow}Lv.{$level}{$this->reset}");
$out->writeln("描述: {$spellInfo['desc']}");
$out->writeln("");
// 显示法术效果信息
$type = $spellInfo['type'] ?? '';
$baseCost = $spellInfo['cost'] ?? 0;
$upgrades = $spellsData['upgrades'] ?? [];
$upgradeInfo = $upgrades[$level] ?? [];
$costReduction = $upgradeInfo['cost_reduction'] ?? 0;
$actualCost = max(1, $baseCost - $costReduction);
$out->writeln("{$this->green}基础消耗: {$baseCost} → 当前消耗: {$actualCost}{$this->reset}");
if ($type === 'damage_single') {
$damage = $spellInfo['damage'] ?? 1.0;
$damageBonus = $upgradeInfo['damage_bonus'] ?? 0;
$actualDamage = $damage * (1 + $damageBonus / 100);
$out->writeln("伤害倍数: {$this->yellow}" . number_format($damage, 2) . "{$this->reset}{$this->green}" . number_format($actualDamage, 2) . "x{$this->reset}");
$out->writeln("效果: {$this->magenta}对单个敌人造成魔法伤害{$this->reset}");
} elseif ($type === 'damage_aoe') {
$damage = $spellInfo['damage'] ?? 1.0;
$damageBonus = $upgradeInfo['damage_bonus'] ?? 0;
$actualDamage = $damage * (1 + $damageBonus / 100);
$out->writeln("伤害倍数: {$this->yellow}" . number_format($damage, 2) . "{$this->reset}{$this->green}" . number_format($actualDamage, 2) . "x{$this->reset}");
$out->writeln("效果: {$this->magenta}对所有敌人造成魔法伤害{$this->reset}");
} elseif ($type === 'support') {
$subtype = $spellInfo['subtype'] ?? '';
if ($subtype === 'heal' || $subtype === 'heal_all') {
$heal = $spellInfo['heal'] ?? 0.5;
$healBase = $spellInfo['heal_base'] ?? 20;
$out->writeln("恢复效果: {$this->green}魔攻 x {$heal} + {$healBase}{$this->reset}");
$out->writeln("效果: {$this->magenta}恢复生命值{$this->reset}");
} elseif ($subtype === 'defend') {
$defenseBoos = $spellInfo['defense_boost'] ?? 0;
$out->writeln("防御增加: {$this->green}+{$defenseBoos}{$this->reset}");
$out->writeln("效果: {$this->magenta}增加防御力{$this->reset}");
}
}
$out->writeln("");
Screen::pause($out);
}
/**
* 学习法术
*/
private function learnSpell(array $spellsData)
{
$out = $this->game->output;
$player = $this->game->player;
Screen::clear($out);
$out->writeln("{$this->bold}{$this->cyan}=== 学习法术 ==={$this->reset}");
$out->writeln("");
// 获取所有可学习的法术(按品质分类)
$allSpells = [];
foreach ($spellsData as $category => $spells) {
if (is_array($spells) && $category !== 'quality_levels' && $category !== 'upgrades') {
foreach ($spells as $spellId => $spellInfo) {
if (is_numeric($spellId)) {
$allSpells[$spellId] = $spellInfo;
}
}
}
}
// 显示可以学习的法术
$learnableIndex = 0;
$learnableSpells = [];
foreach ($allSpells as $spellId => $spellInfo) {
// 检查是否已学习
if ($player->hasSpell($spellId)) {
continue;
}
// 检查等级要求
$levelReq = $spellInfo['level_req'] ?? 1;
if ($player->level < $levelReq) {
continue;
}
// 检查是否有资源书
$bookCount = $player->getSpellBookCount($spellId);
if ($bookCount < 1) {
continue;
}
$learnableIndex++;
$quality = $spellInfo['quality'] ?? 'common';
$qualityColor = $this->getQualityColor($quality);
$name = $spellInfo['name'] ?? '未知法术';
$out->writeln("[{$learnableIndex}] {$qualityColor}{$name}{$this->reset} (需求等级: {$levelReq})");
$learnableSpells[$learnableIndex] = ['spellId' => $spellId, 'spellInfo' => $spellInfo];
}
if (empty($learnableSpells)) {
$out->writeln("{$this->yellow}暂无可学习的法术(需要有资源书并满足等级要求){$this->reset}");
Screen::delay(1000000);
return;
}
$out->writeln("[0] 返回");
$choice = Input::ask($this->game->output, "请选择: ");;
if ($choice == '0') {
return;
}
if (isset($learnableSpells[$choice])) {
$selected = $learnableSpells[$choice];
$spellId = $selected['spellId'];
// 消耗资源书
$player->spendSpellBooks($spellId, 1);
// 学习法术
if ($player->learnSpell($spellId)) {
$out->writeln("{$this->green}✓ 成功学习 {$selected['spellInfo']['name']}{$this->reset}");
} else {
$out->writeln("{$this->red}✗ 学习失败{$this->reset}");
}
Screen::delay(1000000);
} else {
$out->writeln("{$this->red}无效选择{$this->reset}");
Screen::delay(500000);
}
}
/**
* 升级法术
*/
private function upgradeSpell(array $spellsData)
{
$out = $this->game->output;
$in = $this->game->input;
$player = $this->game->player;
Screen::clear($out);
$out->writeln("{$this->bold}{$this->cyan}=== 升级法术 ==={$this->reset}");
$out->writeln("");
if (empty($player->spells)) {
$out->writeln("{$this->red}还未学习任何法术{$this->reset}");
Screen::delay(1000000);
return;
}
// 列出已学习但未满级的法术
$upgradableIndex = 0;
$upgradableSpells = [];
$upgrades = $spellsData['upgrades'] ?? [];
foreach ($player->spells as $spellId => $spellData) {
$level = $spellData['level'] ?? 1;
// 检查是否已满级
if ($level >= 10) {
continue;
}
$spellInfo = $this->getSpellInfo($spellId, $spellsData);
$quality = $spellInfo['quality'] ?? 'common';
$qualityColor = $this->getQualityColor($quality);
$name = $spellInfo['name'] ?? '未知法术';
// 获取升级所需资源书数量
$nextLevel = $level + 1;
$upgradeInfo = $upgrades[$nextLevel] ?? ['cost' => 0];
$booksNeeded = $upgradeInfo['cost'] ?? 0;
$booksOwned = $player->getSpellBookCount($spellId);
$upgradableIndex++;
$canUpgrade = $booksOwned >= $booksNeeded;
$statusColor = $canUpgrade ? $this->green : $this->red;
$out->writeln("[{$upgradableIndex}] {$qualityColor}{$name}{$this->reset} Lv.{$level}");
$out->writeln(" 升级所需: {$statusColor}{$booksNeeded}{$this->reset} 本资源书 (拥有: {$booksOwned})");
$upgradableSpells[$upgradableIndex] = ['spellId' => $spellId, 'spellInfo' => $spellInfo];
}
if (empty($upgradableSpells)) {
$out->writeln("{$this->yellow}暂无可升级的法术{$this->reset}");
Screen::delay(1000000);
return;
}
$out->writeln("[0] 返回");
$choice = Input::ask($out,"请选择要升级的法术");
if ($choice == '0') {
return;
}
if (isset($upgradableSpells[$choice])) {
$selected = $upgradableSpells[$choice];
$spellId = $selected['spellId'];
$level = $player->getSpellLevel($spellId);
$nextLevel = $level + 1;
$upgradeInfo = $upgrades[$nextLevel] ?? ['cost' => 0];
$booksNeeded = $upgradeInfo['cost'] ?? 0;
// 检查是否有足够的资源书
if (!$player->spendSpellBooks($spellId, $booksNeeded)) {
$out->writeln("{$this->red}✗ 资源书不足!{$this->reset}");
Screen::delay(1000000);
return;
}
// 升级法术
if ($player->upgradeSpell($spellId)) {
$out->writeln("{$this->green}✓ 成功升级 {$selected['spellInfo']['name']} 至 Lv.{$nextLevel}{$this->reset}");
} else {
$out->writeln("{$this->red}✗ 升级失败{$this->reset}");
}
Screen::delay(1000000);
} else {
$out->writeln("{$this->red}无效选择{$this->reset}");
Screen::delay(500000);
}
}
/**
* 获取魔法值进度条
*/
private function getManaBar(int $current, int $max): string
{
$percent = ($current / $max) * 100;
$filled = (int)(20 * ($current / $max));
$empty = 20 - $filled;
$color = $percent >= 50 ? $this->green : ($percent >= 25 ? $this->yellow : $this->red);
return "{$color}[" . str_repeat('█', $filled) . str_repeat('░', $empty) . "]{$this->reset} " . number_format($percent, 0) . "%";
}
/**
* 获取法术的品质颜色
*/
private function getQualityColor(string $quality): string
{
$map = [
'common' => Colors::WHITE,
'rare' => Colors::BLUE,
'epic' => Colors::MAGENTA,
'legendary' => Colors::YELLOW,
];
return $map[$quality] ?? $this->white;
}
/**
* 获取品质名称
*/
private function getQualityName(string $quality): string
{
$map = [
'common' => '普通',
'rare' => '稀有',
'epic' => '史诗',
'legendary' => '传奇',
];
return $map[$quality] ?? '未知';
}
/**
* 获取法术信息
*/
private function getSpellInfo(int $spellId, array $spellsData): ?array
{
foreach ($spellsData as $category => $spells) {
if (is_array($spells) && $category !== 'quality_levels' && $category !== 'upgrades') {
if (isset($spells[$spellId])) {
return $spells[$spellId];
}
}
}
return null;
}
}