52 lines
2.8 KiB
GDScript
52 lines
2.8 KiB
GDScript
class_name DamageCalculator
|
|
extends RefCounted
|
|
|
|
const CRIT_CHANCES : Array[float] = [1.0 / 24.0, 1.0 / 8.0, 1.0 / 2.0, 1.0] #selon le bonus de critique de la capacite (0 a 3)
|
|
const CRIT_MULTIPLIER : float = 1.5
|
|
const STAB_MULTIPLIER : float = 1.5
|
|
const SPREAD_MULTIPLIER : float = 0.75 #capacite touchant plusieurs cibles
|
|
|
|
static func calculate(attacker : BattleMon, defender : BattleMon, move : MoveData, rng : RandomNumberGenerator = null, spread : bool = false, deterministic : bool = false) -> Dictionary:
|
|
#renvoie {"damage": int, "effectiveness": float, "critical": bool}
|
|
var result : Dictionary = {"damage": 0, "effectiveness": 1.0, "critical": false}
|
|
if move.power <= 0 or move.category == "status": return result
|
|
|
|
var effectiveness : float = TypeChart.get_multiplier(move.type, defender.get_types())
|
|
result["effectiveness"] = effectiveness
|
|
if effectiveness == 0.0: return result
|
|
|
|
var physical : bool = move.category == "physical"
|
|
var attack : float = attacker.get_stat(PokemonNature.Stat.ATTACK if physical else PokemonNature.Stat.SP_ATTACK)
|
|
var defense : float = defender.get_stat(PokemonNature.Stat.DEFENSE if physical else PokemonNature.Stat.SP_DEFENSE)
|
|
var level : int = attacker.pokemon.level
|
|
|
|
#formule officielle
|
|
var damage : float = floorf(floorf(floorf(2.0 * level / 5.0 + 2.0) * move.power * attack / maxf(defense, 1.0)) / 50.0) + 2.0
|
|
|
|
var critical : bool = !deterministic and rng != null and rng.randf() < CRIT_CHANCES[clampi(move.crit_rate, 0, 3)]
|
|
var roll : float = 0.925 if (deterministic or rng == null) else rng.randi_range(85, 100) / 100.0
|
|
var stab : float = STAB_MULTIPLIER if attacker.get_types().has(move.type.to_lower()) else 1.0
|
|
|
|
damage *= roll * stab * effectiveness
|
|
if attacker.field != null: damage *= attacker.field.damage_multiplier(move.type.to_lower())
|
|
for effect in attacker.get_effects():
|
|
damage = effect.modify_outgoing_damage(attacker, defender, move, damage)
|
|
if critical: damage *= CRIT_MULTIPLIER
|
|
if spread: damage *= SPREAD_MULTIPLIER
|
|
|
|
result["critical"] = critical
|
|
result["damage"] = maxi(1, floori(damage))
|
|
return result
|
|
|
|
static func estimate(attacker : BattleMon, defender : BattleMon, move : MoveData, spread : bool = false) -> int:
|
|
#degats attendus, sans hasard (utilise par l'IA)
|
|
return int(calculate(attacker, defender, move, null, spread, true)["damage"])
|
|
|
|
static func confusion_damage(mon : BattleMon, rng : RandomNumberGenerator) -> int:
|
|
#le pokemon confus se blesse : capacite physique de puissance 40, sans type ni critique
|
|
var attack : float = mon.get_stat(PokemonNature.Stat.ATTACK)
|
|
var defense : float = mon.get_stat(PokemonNature.Stat.DEFENSE)
|
|
var damage : float = floorf(floorf(floorf(2.0 * mon.pokemon.level / 5.0 + 2.0) * 40.0 * attack / maxf(defense, 1.0)) / 50.0) + 2.0
|
|
damage *= rng.randi_range(85, 100) / 100.0
|
|
return maxi(1, floori(damage))
|