优化
This commit is contained in:
parent
cd98a5a452
commit
81402717b5
|
|
@ -13,8 +13,8 @@ class Actor
|
|||
public int $maxHp = 100;
|
||||
public int $patk = 10;
|
||||
public int $matk = 10;
|
||||
public int $pdef = 10;
|
||||
public int $mdef = 10;
|
||||
public int $pdef = 5;
|
||||
public int $mdef = 3;
|
||||
public int $crit = 0;
|
||||
public float $critdmg = 110.0;
|
||||
|
||||
|
|
@ -136,11 +136,10 @@ class Actor
|
|||
|
||||
public function fullHeal(): void
|
||||
{
|
||||
if (property_exists($this, 'maxHp')) {
|
||||
$this->hp = $this->maxHp;
|
||||
} elseif (property_exists($this, 'baseHp')) {
|
||||
$this->hp = $this->baseHp;
|
||||
}
|
||||
$status = $this->getStats();
|
||||
|
||||
$this->hp = $status['maxHp'];
|
||||
|
||||
}
|
||||
|
||||
public function recoverMana(int $amount): int
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Game\Entities;
|
||||
|
||||
use Game\Modules\Bag\Consume;
|
||||
use Game\Modules\Bag\Equipment;
|
||||
use Game\Modules\Bag\Spell;
|
||||
|
||||
|
|
@ -19,20 +20,16 @@ class Monster extends Actor
|
|||
|
||||
// Monster特有的掉落表
|
||||
public array $dropTable = [];
|
||||
private bool $is_elite;
|
||||
private bool $is_boss;
|
||||
|
||||
public static function create(int $dungeonId): self
|
||||
{
|
||||
// Load data
|
||||
static $maps = null;
|
||||
if ($maps === null) {
|
||||
$maps = require __DIR__ . '/../../src/Data/maps.php';
|
||||
}
|
||||
$monsterConfig = self::getMasters($dungeonId);
|
||||
|
||||
$monster = new self();
|
||||
|
||||
// 1. Get monster list for this dungeon
|
||||
$monsterConfig = $maps[$dungeonId]['monsters'] ?? [];
|
||||
|
||||
if (empty($monsterConfig)) {
|
||||
$monster->name = '未知怪物';
|
||||
$monster->expReward = 10;
|
||||
|
|
@ -76,12 +73,8 @@ class Monster extends Actor
|
|||
public static function createGroup(int $dungeonId,$play_level): array
|
||||
{
|
||||
// Load data
|
||||
static $maps = null;
|
||||
if ($maps === null) {
|
||||
$maps = require __DIR__ . '/../../src/Data/maps.php';
|
||||
}
|
||||
$monsterConfig = self::getMasters($dungeonId);
|
||||
|
||||
$monsterConfig = $maps[$dungeonId]['monsters'] ?? [];
|
||||
if (empty($monsterConfig)) {
|
||||
return [self::create($dungeonId)];
|
||||
}
|
||||
|
|
@ -130,7 +123,8 @@ class Monster extends Actor
|
|||
$monster = new self();
|
||||
// Create monster from selected config
|
||||
$monster->hydrateFromConfig($selectedConfig,$dungeonId);
|
||||
|
||||
$status = $monster->getStats();
|
||||
$monster->hp = $status['maxHp'];
|
||||
// Add suffix to distinguish multiple monsters of same type
|
||||
if ($groupSize > 1) {
|
||||
$monster->name .= " (" . ($i) . ")";
|
||||
|
|
@ -145,6 +139,7 @@ class Monster extends Actor
|
|||
public function hydrateFromConfig(array $config,$dungeonId): void
|
||||
{
|
||||
$this->name = $config['name'];
|
||||
|
||||
$this->level = $config['level'] ?? 1;
|
||||
$this->baseHp = $config['hp'] ?? 20;
|
||||
$this->hp = $this->baseHp;
|
||||
|
|
@ -161,7 +156,8 @@ class Monster extends Actor
|
|||
$this->critdmg = $config['critdmg'] ?? 130;
|
||||
$this->expReward = $config['exp'] ?? 0;
|
||||
$this->spiritStoneReward = $config['spirit_stones'] ?? 0;
|
||||
|
||||
$this->is_elite = $config['is_elite'] ?? false;
|
||||
$this->is_boss = $config['is_boss'] ?? false;
|
||||
// 根据等级和基础属性分配天赋点
|
||||
$this->allocateTalentsByLevel();
|
||||
static $allItems = null;
|
||||
|
|
@ -169,12 +165,17 @@ class Monster extends Actor
|
|||
$allItems = json_decode(file_get_contents(__DIR__.'/../Data/items_new.json'),true);
|
||||
}
|
||||
$drops = $config['drops'] ?? [];
|
||||
$index = ($dungeonId - 1) * 5;
|
||||
$drops_eq = array_slice($allItems,$index,5);
|
||||
$drops_eq =$allItems[$dungeonId - 1];
|
||||
$drops = array_merge($drops,$drops_eq);
|
||||
foreach ($drops as $drop) {
|
||||
$type = $drop['type'] ?? '';
|
||||
$rate = $drop['rate'] ?? 20;
|
||||
if ($this->is_elite){
|
||||
$rate += 20;
|
||||
}
|
||||
if ($this->is_boss){
|
||||
$rate += 40;
|
||||
}
|
||||
if (in_array($type, ['weapon', 'armor', 'boots', 'ring', 'necklace'])) {
|
||||
if (rand(1, 100) > $rate) continue;
|
||||
$spec = $drop;
|
||||
|
|
@ -183,6 +184,7 @@ class Monster extends Actor
|
|||
$this->equip[$type] = $equip;
|
||||
}
|
||||
}
|
||||
$this->dropTable[] = Consume::createItem($dungeonId,$config['level']);
|
||||
// 为怪物配置法术
|
||||
$this->generateSpells($config);
|
||||
|
||||
|
|
@ -246,6 +248,16 @@ class Monster extends Actor
|
|||
}
|
||||
}
|
||||
|
||||
private static function getMasters(int $dungeonId)
|
||||
{
|
||||
$data = file_get_contents(__DIR__.'/../Data/monster.json');
|
||||
$data = json_decode($data,true);
|
||||
// dd($data);
|
||||
$monsters = $data["region_{$dungeonId}_monsters"];
|
||||
$boss = $data["region_{$dungeonId}_bosses"];
|
||||
return array_merge($monsters,$boss);
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机掉落装备物品(从穿着的装备随机掉落)
|
||||
* @param int $dropRate 掉落概率(0-100)
|
||||
|
|
|
|||
|
|
@ -10,153 +10,19 @@ use Game\Core\Colors;
|
|||
class Consume extends Item
|
||||
{
|
||||
|
||||
private static array $typeNames = [
|
||||
'heal_single' => '单体治疗',
|
||||
'damage_single' => '单体伤害',
|
||||
'damage_aoe' => '群体伤害',
|
||||
'heal_aoe' => '群体治疗',
|
||||
'support' => '辅助',
|
||||
];
|
||||
|
||||
|
||||
|
||||
// 计算方式说明
|
||||
private static array $calcTypeDescriptions = [
|
||||
'matk' => '基于魔攻',
|
||||
'patk' => '基于物攻',
|
||||
'hp_percent' => '基于最大生命值百分比',
|
||||
'hybrid' => '基于(魔攻+物攻)混合',
|
||||
'crit_heal' => '暴击率影响治疗效果',
|
||||
'crit_damage' => '暴击伤害系数影响伤害',
|
||||
'crit_aoe' => '暴击率影响范围伤害',
|
||||
'defense' => '基于防御属性',
|
||||
'def_pierce' => '防御穿透伤害',
|
||||
'status_bonus' => '目标状态加成伤害',
|
||||
'enemy_count_bonus' => '敌人数量加成伤害',
|
||||
'dispersed_damage' => '伤害分散到所有敌人',
|
||||
'smart_heal' => '智能治疗(优先低血量)',
|
||||
'hp_missing' => '基于缺失生命值',
|
||||
'low_def_bonus' => '对低防御敌人伤害加成',
|
||||
'matk_scaled' => '随敌人数量加成',
|
||||
'team_sync' => '基于队伍规模',
|
||||
];
|
||||
/**
|
||||
* 创建法术物品 - 支持新的丰富法术系统
|
||||
* @param int $spellId 法术ID
|
||||
* @param int $level 物品等级
|
||||
* @return array 法术物品数组
|
||||
*/
|
||||
public static function createItem(int $spellId, int $level = 1): array
|
||||
public static function createItem(int $dungeonId, int $level = 1): array
|
||||
{
|
||||
static $spellsData = null;
|
||||
if ($spellsData === null) {
|
||||
$spellsData = require __DIR__ . '/../../../src/Data/spells.php';
|
||||
}
|
||||
|
||||
// 随机品质
|
||||
$roll = rand(1, 100);
|
||||
// $roll = 100;
|
||||
if ($roll <= 70) $quality = 'common';
|
||||
elseif ($roll <= 90) $quality = 'rare';
|
||||
elseif ($roll <= 98) $quality = 'epic';
|
||||
else $quality = 'legendary';
|
||||
// 查找法术信息
|
||||
$spellInfo = null;
|
||||
foreach ($spellsData as $category => $spells) {
|
||||
if (is_array($spells) && !in_array($category, ['quality_levels', 'upgrades', 'dungeon_spell_drops', 'quality_drop_rates', 'spells_by_quality'])) {
|
||||
if (isset($spells[$spellId])) {
|
||||
$spellInfo = $spells[$spellId];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$spellInfo) {
|
||||
// 默认法术
|
||||
return [
|
||||
'id' => uniqid('spell_'),
|
||||
'type' => 'spell',
|
||||
'name' => '未知法术',
|
||||
'quality' => $quality,
|
||||
'level' => $level,
|
||||
'spellId' => $spellId,
|
||||
'enhanceLevel' => 0,
|
||||
'calc_type' => 'matk',
|
||||
'cost' => 20,
|
||||
'spellType' => 'damage_single',
|
||||
'desc' => '未知的法术',
|
||||
];
|
||||
}
|
||||
|
||||
// 品质映射到数组索引 (common=0, rare=1, epic=2, legendary=3)
|
||||
$qualityIndex = match ($quality) {
|
||||
'common' => 0,
|
||||
'rare' => 1,
|
||||
'epic' => 2,
|
||||
'legendary' => 3,
|
||||
default => 0,
|
||||
};
|
||||
|
||||
// 提取品质相关的参数
|
||||
$healRatio = $spellInfo['heal_ratio'][$qualityIndex] ?? ($spellInfo['heal_ratio'][0] ?? 0);
|
||||
$damageRatio = $spellInfo['damage_ratio'][$qualityIndex] ?? ($spellInfo['damage_ratio'][0] ?? 1.0);
|
||||
$healBase = $spellInfo['heal_base'][$qualityIndex] ?? ($spellInfo['heal_base'][0] ?? 0);
|
||||
$critBonus = $spellInfo['crit_bonus'][$qualityIndex] ?? ($spellInfo['crit_bonus'][0] ?? 0);
|
||||
$critDmgBonus = $spellInfo['crit_dmg_bonus'][$qualityIndex] ?? ($spellInfo['crit_dmg_bonus'][0] ?? 0);
|
||||
$enemyCountBonus = $spellInfo['enemy_count_bonus'][$qualityIndex] ?? ($spellInfo['enemy_count_bonus'][0] ?? 0);
|
||||
$dispersion = $spellInfo['dispersion'][$qualityIndex] ?? ($spellInfo['dispersion'][0] ?? 1.0);
|
||||
$teamBonus = $spellInfo['team_bonus'][$qualityIndex] ?? ($spellInfo['team_bonus'][0] ?? 0);
|
||||
$priorityBonus = $spellInfo['priority_bonus'][$qualityIndex] ?? ($spellInfo['priority_bonus'][0] ?? 0);
|
||||
|
||||
// 计算基础伤害值(根据法术模板的基础值和成长系数)
|
||||
$baseValue = 0;
|
||||
$growth = 0;
|
||||
if (isset($spellInfo['base']) && isset($spellInfo['growth'])) {
|
||||
$baseArray = $spellInfo['base'];
|
||||
|
||||
$growthArray = $spellInfo['growth'];
|
||||
|
||||
// 确保索引在范围内
|
||||
if (is_array($baseArray) && is_array($growthArray)) {
|
||||
$baseValue = $baseArray[$qualityIndex] ?? ($baseArray[0] ?? 0);
|
||||
$growth = $growthArray[$qualityIndex] ?? ($growthArray[0] ?? 0);
|
||||
|
||||
// 应用计算公式:finalValue = baseValue + (level * growth) + randomBonus
|
||||
$randomBonus = rand(0, max(1, (int)($baseValue * 3)));
|
||||
$finalBaseValue = (int)($baseValue + ($level * $growth * 10) + $randomBonus);
|
||||
} else {
|
||||
$finalBaseValue = 0;
|
||||
}
|
||||
} else {
|
||||
$finalBaseValue = 0;
|
||||
}
|
||||
|
||||
$data = file_get_contents(__DIR__.'/../../Data/consume.json');
|
||||
$data = json_decode($data,true);
|
||||
$name = $data[$dungeonId]['name'];
|
||||
$heal = $level * 10 * 3;
|
||||
return [
|
||||
'id' => uniqid('spell_'),
|
||||
'type' => 'spell',
|
||||
'name' => $spellInfo['name'],
|
||||
'quality' => $quality,
|
||||
'level' => $level,
|
||||
'spellId' => $spellId,
|
||||
'enhanceLevel' => 0,
|
||||
'calc_type' => $spellInfo['calc_type'] ?? 'matk',
|
||||
'cost' => $spellInfo['cost'] ?? 20,
|
||||
'spellType' => $spellInfo['type'] ?? 'damage_single',
|
||||
'desc' => $spellInfo['desc'] ?? '',
|
||||
|
||||
// 品质参数
|
||||
'heal_ratio' => $healRatio,
|
||||
'damage_ratio' => $damageRatio,
|
||||
'heal_base' => $healBase,
|
||||
'crit_bonus' => $critBonus,
|
||||
'crit_dmg_bonus' => $critDmgBonus,
|
||||
'enemy_count_bonus' => $enemyCountBonus,
|
||||
'dispersion' => $dispersion,
|
||||
'team_bonus' => $teamBonus,
|
||||
'priority_bonus' => $priorityBonus,
|
||||
// 基础伤害值(已计算)
|
||||
'base' => $finalBaseValue,
|
||||
'growth' => $growth,
|
||||
'id' => uniqid('consume_'),
|
||||
'type' => 'consume',
|
||||
'rate' => 30,
|
||||
'heal' => $heal,
|
||||
'name' => $name,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -171,84 +37,11 @@ class Consume extends Item
|
|||
|
||||
public static function getLineShow($item): string
|
||||
{
|
||||
$parts = [];
|
||||
$spell = $item;
|
||||
// 名称(带品质颜色和强化)
|
||||
$parts[] = self::formatName($spell);
|
||||
|
||||
// 法术类型
|
||||
$spellType = $spell['spellType'] ?? $spell['type'] ?? 'unknown';
|
||||
$typeName = self::$typeNames[$spellType];
|
||||
$parts[] = Colors::GRAY . "[{$typeName}]" . Colors::RESET;
|
||||
|
||||
// 计算方式
|
||||
$calcType = $spell['calc_type'] ?? 'matk';
|
||||
$calcDesc = self::getCalcTypeDescription($calcType);
|
||||
$ratio = $spell['damage_ratio'];
|
||||
$parts[] = Colors::GRAY . "{$calcDesc} x $ratio" . Colors::RESET;
|
||||
// 基础值
|
||||
$base = $spell['base'] ?? 0;
|
||||
$parts[] = Colors::YELLOW . "基础:{$base}" . Colors::RESET;
|
||||
|
||||
// 消耗
|
||||
$cost = $spell['cost'] ?? 0;
|
||||
$enhanceLevel = $spell['enhanceLevel'] ?? 0;
|
||||
$actualCost = max(1, $cost - ($enhanceLevel * 2));
|
||||
if ($enhanceLevel > 0) {
|
||||
$parts[] = Colors::CYAN . "消耗:{$actualCost}(原:{$cost})" . Colors::RESET;
|
||||
} else {
|
||||
$parts[] = Colors::CYAN . "消耗:{$cost}" . Colors::RESET;
|
||||
}
|
||||
|
||||
return implode(" ", $parts);
|
||||
}
|
||||
|
||||
public static function getCalcTypeDescription(string $calcType): string
|
||||
{
|
||||
return self::$calcTypeDescriptions[$calcType] ?? $calcType;
|
||||
}
|
||||
|
||||
public static function formatName(array $spell): string
|
||||
{
|
||||
$quality = $spell['quality'] ?? 'common';
|
||||
$color = Colors::getColor($quality);
|
||||
$name = $spell['name'] ?? '未知法术';
|
||||
$level = $spell['level'] ?? 1;
|
||||
|
||||
$enhanceLevel = $spell['enhanceLevel'] ?? 0;
|
||||
$enhanceStr = $enhanceLevel > 0 ? Colors::YELLOW . "+{$enhanceLevel}" . Colors::RESET : "";
|
||||
|
||||
return $color . $name . Colors::RESET . " Lv.{$level}" . $enhanceStr;
|
||||
return $item['name'] . '+' .$item['heal'];
|
||||
}
|
||||
|
||||
public static function getDetailShow($item): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function getBaseValue(string $quality, string $type, int $level,bool $isMain = true): float
|
||||
{
|
||||
$qualityMultiplier = match ($quality) {
|
||||
'legendary' => 2.0,
|
||||
'epic' => 1.5,
|
||||
'rare' => 1.2,
|
||||
default => 1.0
|
||||
};
|
||||
|
||||
$base = rand(2*$level, 8*$level);
|
||||
$multiplier = match ($type) {
|
||||
'heal_single' => [1.5, 2],
|
||||
'damage_single' => [1.5, 2],
|
||||
'damage_aoe' => [1.0, 1.3],
|
||||
'heal_aoe' => [1.0, 1.3],
|
||||
default => [1, 1.1]
|
||||
};
|
||||
$random = random_int(1, 10);
|
||||
$multiplier = ($multiplier[1] - $multiplier[0]) * $random / 10 + $multiplier[0];
|
||||
if ($isMain){
|
||||
return floor(($base + ($level * $multiplier)) * $qualityMultiplier);
|
||||
}else{
|
||||
return floor(($base + ($level * $multiplier)) * $qualityMultiplier / 5 * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Game\Modules\Bag;
|
||||
|
||||
use Game\Core\Colors;
|
||||
|
||||
/**
|
||||
* Simple representation of an equipment/consumable item.
|
||||
*/
|
||||
|
|
@ -11,6 +13,7 @@ abstract class Item
|
|||
public string $type; // weapon, armor, consume
|
||||
public string $quality; // common, rare, epic, legendary
|
||||
public string $desc = '';
|
||||
|
||||
public abstract function toArray(): array;
|
||||
|
||||
public abstract static function getLineShow($item): string;
|
||||
|
|
@ -21,25 +24,31 @@ abstract class Item
|
|||
|
||||
public static function show($item): string
|
||||
{
|
||||
if ($item['type'] == 'spell'){
|
||||
if (!$item) {
|
||||
return '无';
|
||||
}
|
||||
if ($item['type'] == 'potion_pool') {
|
||||
return Colors::GREEN.'小绿瓶+'.$item['heal'].Colors::RESET;
|
||||
} else if ($item['type'] == 'spell') {
|
||||
return Spell::getLineShow($item);
|
||||
}elseif($item['type'] == 'quest'){
|
||||
} elseif ($item['type'] == 'quest') {
|
||||
return Quest::getLineShow($item);
|
||||
}elseif ($item['type'] == 'consume'){
|
||||
} elseif ($item['type'] == 'consume') {
|
||||
return Consume::getLineShow($item);
|
||||
}else{
|
||||
} else {
|
||||
return Equipment::getLineShow($item);
|
||||
}
|
||||
}
|
||||
|
||||
public static function calcPrice($item): int
|
||||
{
|
||||
if ($item['type'] == 'spell'){
|
||||
if ($item['type'] == 'spell') {
|
||||
return Spell::calculateSellPrice($item);
|
||||
}elseif($item['type'] == 'quest'){
|
||||
} elseif ($item['type'] == 'quest') {
|
||||
return Quest::calculateSellPrice($item);
|
||||
}elseif ($item['type'] == 'consume'){
|
||||
} elseif ($item['type'] == 'consume') {
|
||||
return Consume::calculateSellPrice($item);
|
||||
}else{
|
||||
} else {
|
||||
return Equipment::calculateSellPrice($item);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,14 @@
|
|||
namespace Game\Modules;
|
||||
|
||||
use Game\Core\Game;
|
||||
use Game\Core\Input;
|
||||
use Game\Core\Screen;
|
||||
use Game\Core\ItemDisplay;
|
||||
use Game\Core\SpellDisplay;
|
||||
use Game\Core\SpellCalculator;
|
||||
use Game\Core\Colors;
|
||||
use Game\Core\WebInput;
|
||||
use Game\Entities\Player;
|
||||
use Game\Entities\Actor;
|
||||
use Game\Entities\Monster;
|
||||
use Game\Entities\Partner;
|
||||
use Game\Modules\Bag\Equipment;
|
||||
use Game\Modules\Bag\Item;
|
||||
|
||||
class Battle
|
||||
{
|
||||
|
|
@ -132,7 +128,7 @@ class Battle
|
|||
}
|
||||
|
||||
while ($this->player->hp > 0) {
|
||||
Screen::delay(500000, $out);
|
||||
Screen::delay(500000);
|
||||
|
||||
// 创建敌人群组
|
||||
$this->enemies = Monster::createGroup($this->game->dungeonId,$this->player->level);
|
||||
|
|
@ -1061,7 +1057,6 @@ class Battle
|
|||
foreach ($this->enemies as $enemy) {
|
||||
$totalExp += $enemy->expReward;
|
||||
$totalStones += $enemy->spiritStoneReward;
|
||||
|
||||
// 掉落 - 从怪物穿着的装备随机掉落(50%概率)
|
||||
foreach ($enemy->getRandomEquipmentDrops(50) as $item) {
|
||||
$this->player->addItem($item);
|
||||
|
|
@ -1077,7 +1072,7 @@ class Battle
|
|||
// 掉落 - 从掉落表中随机掉落物品
|
||||
foreach ($enemy->dropTable as $drop) {
|
||||
if (rand(1, 100) <= $drop['rate']) {
|
||||
$item = $drop['item'];
|
||||
$item = $drop;
|
||||
// 如果是回复品(消耗品且有heal属性),直接添加到小绿瓶池
|
||||
if ($item['type'] === 'consume' && isset($item['heal']) && $item['heal'] > 0) {
|
||||
$this->player->addPotionPool($item['heal']);
|
||||
|
|
@ -1088,10 +1083,6 @@ class Battle
|
|||
'heal' => $item['heal'],
|
||||
'quantity' => 1
|
||||
];
|
||||
} else {
|
||||
// 其他物品正常添加到背包
|
||||
$this->player->addItem($item);
|
||||
$allDrops[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1139,7 +1130,7 @@ class Battle
|
|||
if (!empty($allDrops)) {
|
||||
$out->writeln("{$this->yellow}║{$this->reset} {$this->white}掉落:{$this->reset}");
|
||||
foreach ($allDrops as $item) {
|
||||
$out->writeln(Equipment::getLineShow($item));
|
||||
$out->writeln(Item::show($item));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,38 +4,12 @@ namespace Game\Modules;
|
|||
use Game\Core\Screen;
|
||||
use Game\Core\Input;
|
||||
use Game\Core\Game;
|
||||
use Game\Modules\Map\Map;
|
||||
|
||||
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);
|
||||
|
|
@ -46,19 +20,11 @@ class DungeonSelectPanel
|
|||
$out->writeln("╚════════════════════════════════════╝");
|
||||
$out->writeln("");
|
||||
|
||||
$maps = require __DIR__ . '/../../src/Data/maps.php';
|
||||
$availableMaps = [];
|
||||
|
||||
$map = new Map($this->game);
|
||||
$maps = $map->getMaps();
|
||||
// 只显示已解锁的地图
|
||||
foreach ($maps as $id => $map) {
|
||||
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("[{$id}] {$map['name']}");
|
||||
}
|
||||
|
||||
$out->writeln("");
|
||||
|
|
@ -77,17 +43,6 @@ class DungeonSelectPanel
|
|||
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;
|
||||
|
|
|
|||
53
src/Modules/Map/Map.php
Normal file
53
src/Modules/Map/Map.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Game\Modules\Map;
|
||||
|
||||
use Game\Core\Game;
|
||||
|
||||
class Map
|
||||
{
|
||||
|
||||
private $game;
|
||||
private $map;
|
||||
public function __construct(Game $game)
|
||||
{
|
||||
$this->game = $game;
|
||||
$data = file_get_contents(__DIR__.'/../../Data/map.json');
|
||||
$this->map = json_decode($data,true);
|
||||
|
||||
}
|
||||
|
||||
public function getMaps()
|
||||
{
|
||||
$res = [];
|
||||
$i = 0;
|
||||
foreach ($this->map as $item){
|
||||
if ($this->canEnterDungeon($item)){
|
||||
$res [++$i] = $item;
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
private function canEnterDungeon(array $map): bool
|
||||
{
|
||||
// 如果没有key_item要求,可以进入
|
||||
if ($map['key_item'] === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查玩家是否拥有该钥匙
|
||||
return $this->hasItem($map['key_item']);
|
||||
}
|
||||
|
||||
private function hasItem(string $itemName): bool
|
||||
{
|
||||
foreach ($this->game->player->inventory as $item) {
|
||||
if (($item['name'] ?? '') === $itemName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -216,34 +216,12 @@ class StatsPanel
|
|||
$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(Item::show($item));
|
||||
}
|
||||
|
||||
$out->writeln("╚════════════════════════════════════╝");
|
||||
|
|
@ -255,23 +233,10 @@ class StatsPanel
|
|||
$out->writeln("╠════════════════════════════════════╣");
|
||||
|
||||
$skillSlots = ['skill1', 'skill2', 'skill3', 'skill4'];
|
||||
$skillIndex = 1;
|
||||
|
||||
foreach ($skillSlots as $slot) {
|
||||
$spell = $actor->skillSlots[$slot] ?? null;
|
||||
if ($spell) {
|
||||
// 法术使用 SpellDisplay 显示
|
||||
$slotLines = SpellDisplay::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(Item::show($spell));
|
||||
}
|
||||
$out->writeln("╚════════════════════════════════════╝");
|
||||
$out->writeln("");
|
||||
|
|
@ -399,7 +364,7 @@ class StatsPanel
|
|||
$displayIdx = 1;
|
||||
$idxMap = [];
|
||||
foreach ($equipableItems as $realIdx => $item) {
|
||||
$displayStr = Item::show($equipableItems);
|
||||
$displayStr = Item::show($item);
|
||||
$this->game->output->writeln("[{$displayIdx}] {$displayStr}");
|
||||
$idxMap[$displayIdx] = $realIdx;
|
||||
$displayIdx++;
|
||||
|
|
|
|||
|
|
@ -2,27 +2,12 @@
|
|||
|
||||
use Game\Modules\Bag\Equipment;
|
||||
use Game\Modules\Bag\Spell;
|
||||
use Game\Modules\Skill\Enums\DamageType;
|
||||
use Game\Modules\Skill\Factories\EffectFactory;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
|
||||
// 效果使用示例
|
||||
|
||||
// 创建伤害效果
|
||||
$damageEffect = EffectFactory::createEffect([
|
||||
'type' => 'damage',
|
||||
'id' => 'fire_ball_damage',
|
||||
'name' => '火球术伤害',
|
||||
'damage_type' => DamageType::FIRE->value,
|
||||
'value' => 150, // 150% 攻击力伤害
|
||||
'is_percentage' => true,
|
||||
'crit_chance' => 0.1,
|
||||
'crit_multiplier' => 2.0,
|
||||
'duration' => 0 // 立即效果
|
||||
]);
|
||||
dd($damageEffect);
|
||||
$res = \Game\Entities\Monster::create(1);
|
||||
dd($res);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user