['affixes' => 0, 'index' => 0], 'rare' => ['affixes' => 1, 'index' => 1], 'epic' => ['affixes' => 2, 'index' => 2], 'legendary' => ['affixes' => 3, 'index' => 3], ]; // 随机品质 $roll = rand(1, 100); if ($roll <= 70) $quality = 'common'; elseif ($roll <= 90) $quality = 'rare'; elseif ($roll <= 98) $quality = 'epic'; else $quality = 'legendary'; $item = new self(); $item->type = $type; $item->quality = $quality; $item->level = $level; $affixCount = $qualityConfig[$quality]['affixes']; $qualityIndex = $qualityConfig[$quality]['index']; $typeConfig = $data['types'][$type] ?? null; if (!$typeConfig) { $item->name = '未知物品'; $item->desc = '未知'; return $item->toArray(); } $names = $typeConfig['names'] ?? ['未知物品']; if ($specificName !== null && in_array($specificName, $names)) { $item->name = $specificName; } else { $item->name = $names[array_rand($names)]; } // 初始化属性 $item->patk = 0; $item->matk = 0; $item->pdef = 0; $item->mdef = 0; $item->hp = 0; $item->crit = 0; $item->critdmg = 0; if ($type === 'consume') { $baseStats = $typeConfig['base_stats'] ?? [0,0,0,0]; $growth = $typeConfig['growth'] ?? 0; $item->heal = $baseStats[$qualityIndex] + ($level * $growth) + rand(0, 10); $item->desc = "Lv.{$level} {$quality}品质的药剂"; } else { // 检查是否有特定物品配置 $specificConfig = $typeConfig['specific_config'][$item->name] ?? []; // 合并配置:优先使用特定配置,否则使用默认配置 $fixedPrimaries = $specificConfig['fixed_primary'] ?? $typeConfig['fixed_primary'] ?? []; $randomPool = $specificConfig['random_primary_pool'] ?? $typeConfig['random_primary_pool'] ?? []; $randomCountConfig = $typeConfig['random_primary_count'][$quality] ?? [0, 0]; // 1. 固定主属性 foreach ($fixedPrimaries as $statKey => $statConfig) { $baseValue = $statConfig['base'][$qualityIndex]; $growth = $statConfig['growth']; $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); $finalValue = (int)($baseValue + ($level * $growth) + $randomBonus); $item->$statKey = $finalValue; } // 2. 随机主属性 if (!empty($randomPool)) { [$minCount, $maxCount] = $randomCountConfig; $randomCount = rand($minCount, $maxCount); if ($randomCount > 0) { $selectedRandoms = []; $availableStats = $randomPool; for ($i = 0; $i < $randomCount && !empty($availableStats); $i++) { $weights = []; foreach ($availableStats as $statKey => $statConfig) { $weights[$statKey] = $statConfig['weight']; } $selectedStat = self::weightedRandom($weights); $selectedRandoms[] = $selectedStat; unset($availableStats[$selectedStat]); } foreach ($selectedRandoms as $statKey) { $statConfig = $randomPool[$statKey]; $baseValue = $statConfig['base'][$qualityIndex]; $growth = $statConfig['growth']; $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); $finalValue = (int)($baseValue + ($level * $growth) + $randomBonus); $item->$statKey += $finalValue; } } } $item->desc = "Lv.{$level} {$quality}品质的" . match($type) { 'weapon' => '武器', 'armor' => '防具', 'boots' => '鞋子', 'ring' => '戒指', 'necklace' => '项链', default => '装备' }; } // 3. 词条 $affixNames = $data['affix_definitions']; $affixWeights = $typeConfig['affix_weights'] ?? []; $item->affixes = []; $selectedAffixes = []; for ($i = 0; $i < $affixCount; $i++) { if ($type == 'consume') break; if (empty($affixWeights)) break; $availableWeights = array_diff_key($affixWeights, array_flip($selectedAffixes)); if (empty($availableWeights)) break; $key = self::weightedRandom($availableWeights); $selectedAffixes[] = $key; $usePercent = (bool)rand(0, 1); if ($usePercent) { $base = rand(2, 8); $v = $base + floor($level / 3); $item->affixes[] = "{$affixNames[$key]} +{$v}%"; } else { $qualityMultiplier = match($quality) { 'legendary' => 2.0, 'epic' => 1.5, 'rare' => 1.2, default => 1.0 }; $base = rand(2, 8); $multiplier = match($key) { 'patk' => 1.5, 'matk' => 1.5, 'pdef' => 1.0, 'mdef' => 1.0, 'hp' => 8, 'crit' => 0.5, 'critdmg' => 0.8, default => 1 }; $v = floor(($base + ($level * $multiplier)) * $qualityMultiplier); $item->affixes[] = "{$affixNames[$key]} +{$v}"; } } return $item->toArray(); } private static function weightedRandom(array $weights): string { $totalWeight = array_sum($weights); $rand = rand(1, $totalWeight); foreach ($weights as $key => $weight) { $rand -= $weight; if ($rand <= 0) return $key; } return array_key_first($weights); } public static function createFromSpec(array $spec, int $baseLevel): array { $type = $spec['type'] ?? 'weapon'; $quality = $spec['quality'] ?? null; $itemLevel = $spec['level'] ?? $baseLevel; $affixes = $spec['affixes'] ?? []; $specificName = $spec['name'] ?? null; $item = self::randomItem($type, $itemLevel, $specificName); if ($quality) $item['quality'] = $quality; if (!empty($affixes)) $item['affixes'] = $affixes; // Allow overriding specific stats if provided in spec (e.g. from maps.php drops) foreach (['patk', 'matk', 'pdef', 'mdef', 'hp', 'crit', 'critdmg'] as $stat) { if (isset($spec[$stat])) { $item[$stat] = $spec[$stat]; } } return $item; } public static function createFromSpecWithConfig(array $spec, int $baseLevel): array { return self::createFromSpec($spec, $baseLevel); } /** * 创建法术物品 - 支持新的丰富法术系统 * @param int $spellId 法术ID * @param string $quality 品质 (common, rare, epic, legendary) * @param int $level 物品等级 * @return array 法术物品数组 */ public static function createSpell(int $spellId, string $quality = 'common', int $level = 1): array { static $spellsData = null; if ($spellsData === null) { $spellsData = require __DIR__ . '/../../src/Data/spells.php'; } // 查找法术信息 $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); 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, ]; } public function toArray(): array { return [ 'name' => $this->name, 'type' => $this->type, 'quality' => $this->quality, 'level' => $this->level, 'patk' => $this->patk, 'matk' => $this->matk, 'pdef' => $this->pdef, 'mdef' => $this->mdef, 'hp' => $this->hp, 'crit' => $this->crit, 'critdmg' => $this->critdmg, 'heal' => $this->heal, 'affixes' => $this->affixes ?? [], 'desc' => $this->desc, ]; } public static function calculateSellPrice(array $item): int { if (($item['type'] ?? '') === 'consume') { $basePrice = match($item['quality'] ?? 'common') { 'common' => 1, 'rare' => 3, 'epic' => 8, 'legendary' => 20, default => 1 }; return (int)($basePrice + ($item['level'] ?? 1) * 0.5); } $basePrice = match($item['quality'] ?? 'common') { 'common' => 5, 'rare' => 15, 'epic' => 40, 'legendary' => 100, default => 5 }; $levelBonus = $basePrice * ($item['level'] ?? 1) * 0.1; $statBonus = 0; $statBonus += ($item['patk'] ?? 0) * 0.5; $statBonus += ($item['matk'] ?? 0) * 0.5; $statBonus += ($item['pdef'] ?? 0) * 0.5; $statBonus += ($item['mdef'] ?? 0) * 0.5; $statBonus += ($item['hp'] ?? 0) * 0.1; $statBonus += ($item['crit'] ?? 0) * 1.0; $statBonus += ($item['critdmg'] ?? 0) * 0.3; $affixCount = count($item['affixes'] ?? []); $affixBonus = $basePrice * $affixCount * 0.2; return max(1, (int)($basePrice + $levelBonus + $statBonus + $affixBonus)); } }