471 lines
17 KiB
PHP
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;
|
|
}
|
|
}
|