184 lines
7.1 KiB
PHP
184 lines
7.1 KiB
PHP
<?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_damage,AOE 暴击率已在上层处理
|
||
$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);
|
||
}
|
||
|
||
$baseDamage += ($spellInfo['base'] ?? 0) * $spellInfo['enhanceLevel'];
|
||
|
||
// 计算防御减免
|
||
$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,
|
||
};
|
||
}
|
||
}
|