Tales-of-PKMN/game/battle/battle_mon.gd

115 lines
4.2 KiB
GDScript

class_name BattleMon
extends RefCounted
#un pokemon en combat : enveloppe autour du PokemonInstance qui porte l'etat TEMPORAIRE du combat
#(boosts, confusion, peur, compteurs...). Disparait au changement de pokemon ou a la fin du combat.
#les PV, le K.O. et le statut principal s'appliquent directement au PokemonInstance (ils persistent).
const MIN_STAGE : int = -6
const MAX_STAGE : int = 6
#noms PokeAPI -> cle dans "stages" (les stats classiques utilisent PokemonNature.Stat)
const STAT_KEYS : Dictionary = {
"attack": PokemonNature.Stat.ATTACK,
"defense": PokemonNature.Stat.DEFENSE,
"special-attack": PokemonNature.Stat.SP_ATTACK,
"special-defense": PokemonNature.Stat.SP_DEFENSE,
"speed": PokemonNature.Stat.SPEED,
"accuracy": &"accuracy",
"evasion": &"evasion",
}
const STAT_LABELS : Dictionary = {
"attack": "L'Attaque",
"defense": "La Défense",
"special-attack": "L'Attaque Spéciale",
"special-defense": "La Défense Spéciale",
"speed": "La Vitesse",
"accuracy": "La Précision",
"evasion": "L'Esquive",
}
var pokemon : PokemonInstance
var slot_id : int = -1
var stages : Dictionary = {} #cle (PokemonNature.Stat, &"accuracy" ou &"evasion") -> -6..6
var volatile : Array[BattleEffect] = [] #effets temporaires : confusion, peur...
var status_turns : int = 0 #sommeil : nombre de tentatives d'action restantes
var toxic_counter : int = 0 #poison grave : nombre de tours ecoules
var acted_this_turn : bool = false
func _init(p_pokemon : PokemonInstance) -> void:
pokemon = p_pokemon
if pokemon.status == PokemonInstance.Status.SLEEP:
status_turns = 2 #deja endormi en entrant en combat
func display_name() -> String:
return pokemon.get_display_name()
func is_fainted() -> bool:
return pokemon.is_fainted()
func get_types() -> Array[String]:
var result : Array[String] = []
for t in pokemon.species.types:
result.append(TypeChart.type_name(t))
return result
#---------- effets ----------
func get_effects() -> Array[BattleEffect]:
#statut principal + effets temporaires (nouveau tableau a chaque appel : on peut modifier pendant l'iteration)
var result : Array[BattleEffect] = []
var status_effect : BattleEffect = StatusRegistry.effect_for(int(pokemon.status))
if status_effect != null: result.append(status_effect)
result.append_array(volatile)
return result
func has_volatile(id : StringName) -> bool:
for e in volatile:
if e.id == id: return true
return false
func add_volatile(effect : BattleEffect) -> void:
volatile.append(effect)
func remove_volatile(id : StringName) -> void:
for i in range(volatile.size() - 1, -1, -1):
if volatile[i].id == id: volatile.remove_at(i)
func cleanup_volatile() -> void:
for i in range(volatile.size() - 1, -1, -1):
if volatile[i].is_expired(): volatile.remove_at(i)
func on_status_applied(status : int, rng : RandomNumberGenerator) -> void:
toxic_counter = 0
status_turns = rng.randi_range(1, 3) if status == PokemonInstance.Status.SLEEP else 0
#---------- statistiques et boosts ----------
func get_stage(key : Variant) -> int:
return int(stages.get(key, 0))
## Applique un changement de boost ; renvoie le changement reellement applique (0 si deja au maximum/minimum).
func change_stage(stat_name : String, delta : int) -> int:
if !STAT_KEYS.has(stat_name): return 0
var key : Variant = STAT_KEYS[stat_name]
var current : int = get_stage(key)
var updated : int = clampi(current + delta, MIN_STAGE, MAX_STAGE)
stages[key] = updated
return updated - current
static func _stage_multiplier(stage : int) -> float:
return (2.0 + stage) / 2.0 if stage >= 0 else 2.0 / (2.0 - stage)
## Stat effective : stat du pokemon x boost, puis modifications des effets (brulure, paralysie...).
func get_stat(stat : PokemonNature.Stat) -> float:
var value : float = pokemon.get_stat(stat) * _stage_multiplier(get_stage(stat))
for effect in get_effects():
value = effect.modify_stat(self, stat, value)
return value
## Multiplicateur de precision de cette attaque contre une cible (boost de precision - esquive).
func accuracy_multiplier_against(target : BattleMon) -> float:
var stage : int = clampi(get_stage(&"accuracy") - target.get_stage(&"evasion"), MIN_STAGE, MAX_STAGE)
return (3.0 + stage) / 3.0 if stage >= 0 else 3.0 / (3.0 - stage)