hanli/src/Core/SpellCalculator.php
2025-12-05 17:38:10 +08:00

182 lines
7.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Game\Core;
class SpellCalculator
{
/**
* 计算法术消耗
*/
public static function calculateCost(array $spellInfo): int
{
$baseCost = $spellInfo['cost'] ?? 20;
$enhanceLevel = $spellInfo['enhanceLevel'] ?? 0;
// 强化减少消耗: 每级 -2
return max(1, $baseCost - ($enhanceLevel * 2));
}
/**
* 计算法术伤害
* @return array ['damage' => int, 'isCrit' => bool, 'baseDamage' => int, 'multiplier' => float]
*/
public static function calculateDamage(array $spellInfo, array $attackerStats, array $defenderStats, int $bonus = 0, bool $isAoe = false): array
{
// 基础倍率
$baseMultiplier = $spellInfo['damage_ratio'] ?? ($spellInfo['damage'] ?? 1.0);
// 实际倍率 (含强化加成)
$actualMultiplier = $baseMultiplier * (1 + $bonus / 100);
// 计算方式
$calcType = $spellInfo['calc_type'] ?? 'matk';
// 基础伤害 (根据 calc_type)
switch ($calcType) {
case 'patk':
$baseDamage = (int)($attackerStats['patk'] * $actualMultiplier);
break;
case 'hybrid':
// 取魔攻与物攻的平均值
$combined = ($attackerStats['matk'] + $attackerStats['patk']) / 2;
$baseDamage = (int)($combined * $actualMultiplier);
break;
case 'low_def_bonus':
// 对低防御目标额外加成 20%
$baseDamage = (int)($attackerStats['matk'] * $actualMultiplier);
$def = $defenderStats['pdef'] ?? 0;
if ($def < 5) {
$baseDamage = (int)($baseDamage * 1.2);
}
break;
case 'matk_scaled':
// 根据敌人数加成,假设 spellInfo 包含 enemy_count_bonus (每个敌人加成比例) 和 enemy_count
$baseDamage = (int)($attackerStats['matk'] * $actualMultiplier);
if (isset($spellInfo['enemy_count_bonus'])) {
$bonusPct = $spellInfo['enemy_count_bonus'];
$enemyCount = $spellInfo['enemy_count'] ?? 1;
$baseDamage = (int)($baseDamage * (1 + $bonusPct * $enemyCount));
}
break;
case 'hp_percent':
// 基于目标最大生命值的百分比
$baseDamage = (int)(($defenderStats['maxHp'] ?? 0) * $actualMultiplier);
break;
case 'defense':
// 基于目标防御属性 (物防+魔防)
$defSum = ($defenderStats['pdef'] ?? 0) + ($defenderStats['mdef'] ?? 0);
$baseDamage = (int)($defSum * $actualMultiplier);
break;
case 'crit_damage':
// 使用物攻作为基础,后续在暴击阶段乘以暴击系数
$baseDamage = (int)($attackerStats['patk'] * $actualMultiplier);
break;
case 'crit_aoe':
// 同 crit_damageAOE 暴击率已在上层处理
$baseDamage = (int)($attackerStats['patk'] * $actualMultiplier);
break;
case 'dispersed_damage':
// 基于魔攻,乘以分散系数 (spellInfo['dispersion'])
$baseDamage = (int)($attackerStats['matk'] * $actualMultiplier);
if (isset($spellInfo['dispersion'])) {
$baseDamage = (int)($baseDamage * $spellInfo['dispersion']);
}
break;
default:
// 默认使用魔攻
$baseDamage = (int)($attackerStats['matk'] * $actualMultiplier);
}
// 计算防御减免
$resistance = $defenderStats['mdef'] ?? 0;
$damage = max(1, $baseDamage - $resistance);
// 暴击计算
$critRate = $attackerStats['crit'] ?? 0;
if ($isAoe) {
$critRate /= 2; // AOE 暴击率减半
}
$isCrit = rand(1, 100) <= $critRate;
if ($isCrit) {
$critDmg = $attackerStats['critdmg'] ?? 150;
$damage = (int)($damage * ($critDmg / 100));
}
return [
'damage' => $damage,
'isCrit' => $isCrit,
'baseDamage' => $baseDamage,
'multiplier' => $baseMultiplier // 返回基础倍率用于显示
];
}
/**
* 计算治疗量
*/
public static function calculateHeal(array $spellInfo, array $casterStats, int $bonus = 0): int
{
// 计算方式
$calcType = $spellInfo['calc_type'] ?? 'matk';
$healRatio = $spellInfo['heal'] ?? 0.5;
$healBase = $spellInfo['heal_base'] ?? 20;
// 基础治疗量 (根据 calc_type)
switch ($calcType) {
case 'patk':
$healAmount = (int)($casterStats['patk'] * $healRatio + $healBase);
break;
case 'hybrid':
$combined = ($casterStats['matk'] + $casterStats['patk']) / 2;
$healAmount = (int)($combined * $healRatio + $healBase);
break;
case 'defense':
$defSum = ($casterStats['pdef'] ?? 0) + ($casterStats['mdef'] ?? 0);
$healAmount = (int)($defSum * $healRatio + $healBase);
break;
case 'hp_percent':
$healAmount = (int)($casterStats['maxHp'] * $healRatio + $healBase);
break;
case 'team_sync':
$teamSize = $spellInfo['team_size'] ?? 1;
$teamBonus = $spellInfo['team_bonus'] ?? 0;
$healAmount = (int)($casterStats['matk'] * $healRatio + $healBase);
$healAmount = (int)($healAmount * (1 + $teamBonus * $teamSize));
break;
case 'smart_heal':
// 智能治疗,先按魔攻计算,后续在 Battle 中会选择低血量目标
$healAmount = (int)($casterStats['matk'] * $healRatio + $healBase);
break;
case 'crit_heal':
$healAmount = (int)($casterStats['matk'] * $healRatio + $healBase);
$critRate = $casterStats['crit'] ?? 0;
$isCrit = rand(1, 100) <= $critRate;
if ($isCrit) {
$critDmg = $casterStats['critdmg'] ?? 150;
$healAmount = (int)($healAmount * ($critDmg / 100));
}
break;
default:
$healAmount = (int)($casterStats['matk'] * $healRatio + $healBase);
break;
}
// 应用强化加成
return (int)($healAmount * (1 + $bonus / 100));
}
/**
* 根据品质获取数组索引
*/
public static function getQualityIndex(string $quality): int
{
return match($quality) {
'common' => 0,
'rare' => 1,
'epic' => 2,
'legendary' => 3,
default => 0,
};
}
}