Aller au contenu principal
Voir

Créer un statut personnalisé

Ce guide explique comment créer un statut personnalisé dans PSDK : déclarer son ID, coder ses méthodes de lecture et d'application, l'enregistrer dans les handlers de combat, créer sa classe d'effet, et ajouter son icône.

Versions requises

Les statuts personnalisés reposent sur l'analyseur de statuts introduit dans PSDK .26.34 et Pokémon Studio 2.4.0. On vérifie que le projet est à jour avant de commencer.

Principe

Un statut est plus qu'une étiquette : le moteur de combat doit savoir comment l'appliquer, l'empêcher, le prendre en compte dans le taux de capture et exécuter son comportement à chaque tour. En créer un touche donc plusieurs couches :

  • Choisir un nom et l'appliquer dans Studio : assigner le statut aux attaques qui doivent l'infliger.
  • Déclarer un ID pour que le moteur dispose d'une référence stable vers le statut.
  • Ajouter des méthodes de lecture et d'application à PFM::Pokemon pour que le reste du code puisse lire et poser le statut.
  • L'enregistrer dans les handlers : le StatusChangeHandler (application, messages, prévention) et, en option, le CatchHandler (bonus de capture).
  • Créer la classe d'effet qui porte le comportement du statut en combat.
  • Ajouter l'icône pour que le statut apparaisse sur l'interface de combat.

Tout au long de ce guide, l'exemple fil rouge est un statut personnalisé affiché Groggy dans Studio, que le moteur résout vers le symbole :custom_groggy (voir ci-dessous). On remplace ce nom et ce symbole par les siens partout où ils apparaissent.

Nommer le statut dans Studio

On choisit un nom clair et on s'y tient : il est réutilisé dans tous les scripts ci-dessous.

Dans Studio, on ouvre chaque attaque qui doit infliger le statut et on le définit comme effet de statut de l'attaque. Quand Studio enregistre un statut personnalisé dans son JSON, il préfixe le nom par Custom_ : un statut nommé Groggy est stocké sous Custom_Groggy.

À la compilation des données, tout nom de statut commençant par Custom_ est mis en minuscules et transformé en symbole. Custom_Groggy devient donc :custom_groggy, le symbole utilisé partout dans le code.

astuce

On réserve dès le départ un nom qui convient. Renommer le statut dans Studio plus tard oblige à mettre à jour tous les scripts qui référencent le symbole.

Déclarer l'ID du statut

Le moteur désigne chaque statut par un ID entier. On ouvre Data/configs/states.json dans le projet avec un éditeur de texte et on ajoute le statut à la table ids :

{
"klass": "Configs::States",
"ids": {
"poison": 1,
"paralysis": 2,
"burn": 3,
"sleep": 4,
"freeze": 5,
"confusion": 6,
"toxic": 8,
"death": 9,
"ko": 9,
"flinch": 7,
"custom_groggy": 20
}
}

On choisit un ID bien au-dessus des existants (20 ici) pour qu'un statut officiel ajouté dans une future version de PSDK ne puisse pas entrer en collision avec le sien. Les statuts officiels s'arrêtent actuellement à 9 : la plage vide entre eux et son ID est donc voulue et sans conséquence. On enregistre le fichier : PSDK recharge automatiquement le .rxdata correspondant.

L'ID est désormais accessible dans le code via Configs.states.ids[:custom_groggy].

Ajouter les méthodes de lecture et d'application sur le Pokémon

PFM::Pokemon expose, pour chaque statut officiel, trois méthodes sur lesquelles le reste du moteur s'appuie. La paralysie sert de modèle :

# Is the Pokemon paralyzed?
# @return [Boolean]
def paralyzed?
return @status == Configs.states.ids[:paralysis]
end

# Paralyze the Pokemon
# @param forcing [Boolean] force the new status
# @return [Boolean] if the pokemon has been paralyzed
def status_paralyze(forcing = false)
if (@status == 0 || forcing) && !dead?
@status = Configs.states.ids[:paralysis]
return true
end
return false
end

# Can the Pokemon be paralyzed?
# @return [Boolean]
def can_be_paralyzed?
return false if @status != 0
return false if type_electric?

return true
end
  • paralyzed? indique si le Pokémon souffre actuellement du statut.
  • status_paralyze(forcing) applique le statut. Par défaut, il ne prend que sur un Pokémon sans statut et non K.O. ; forcing = true contourne ce garde-fou.
  • can_be_paralyzed? décide si le statut peut être appliqué, en tenant compte d'une éventuelle immunité (ici, les types Électrik).

On recrée les trois mêmes méthodes pour son statut dans un script personnalisé. Si on n'a jamais ajouté de script personnalisé, chaque Démo Technique générée par Pokémon Studio fournit un guide dans son dossier scripts.

module PFM
class Pokemon
# Is the Pokemon groggy?
# @return [Boolean]
def groggy?
return @status == Configs.states.ids[:custom_groggy]
end

# Make the Pokemon groggy
# @param forcing [Boolean] force the new status
# @return [Boolean] if the pokemon has been made groggy
def status_groggy(forcing = false)
if (@status == 0 || forcing) && !dead?
@status = Configs.states.ids[:custom_groggy]
return true
end
return false
end

# Can the Pokemon be made groggy?
# @return [Boolean]
def can_be_groggy?
return false if @status != 0
# Add your own immunity conditions here, one per line.

return true
end
end
end

Enregistrer le statut dans le StatusChangeHandler

Battle::Logic::StatusChangeHandler décide si un statut peut être appliqué en combat et, le cas échéant, affiche le bon message et la bonne animation. Plusieurs constantes le pilotent ; toutes sont modifiables, donc on les étend depuis un script personnalisé.

Lier le symbole à sa méthode d'application

STATUS_APPLY_METHODS associe un symbole de statut à la méthode de PFM::Pokemon qui l'applique. On la pointe vers la méthode écrite plus haut :

module Battle
class Logic
class StatusChangeHandler < ChangeHandlerBase
STATUS_APPLY_METHODS[:custom_groggy] = :status_groggy
end
end
end

Déclarer le message et l'animation d'application (optionnel)

STATUS_APPLY_MESSAGE et STATUS_APPLY_ANIMATION portent, respectivement, la ligne de texte et l'animation affichées quand le statut prend :

# Text line for the application message
STATUS_APPLY_MESSAGE[:custom_groggy] = 320
# Animation ID played on application
STATUS_APPLY_ANIMATION[:custom_groggy] = 480

La ligne de message renvoie au fichier de texte 100019 dans Pokémon Studio. On y ajoute son texte d'application avec Studio (jamais en éditant le CSV à la main) et on utilise son numéro de ligne. On ne définit STATUS_APPLY_ANIMATION que si on a réellement une animation prête, sinon on omet cette ligne.

Empêcher le statut sous conditions personnalisées

Quand un statut ne peut pas être appliqué (une immunité, un talent, etc.), le handler doit le refuser et expliquer pourquoi. Il le fait via check_status_prevention, que les modules personnalisés étendent avec prepend :

module GroggyPrevention
# @param status [Symbol] :poison, :toxic, :confusion, :sleep, :freeze, :paralysis, :burn, :flinch
# @param target [PFM::PokemonBattler]
# @param launcher [PFM::PokemonBattler, nil] potential launcher of a move
# @param skill [Battle::Move, nil] potential move used
# @return [:prevent, nil]
def check_status_prevention(status, target, launcher, skill)
result = super
result ||= check_groggy_prevention(status, target, launcher, skill)

return result
end

# Function checking for groggy prevention
# @param status [Symbol] :poison, :toxic, :confusion, :sleep, :freeze, :paralysis, :burn, :flinch
# @param target [PFM::PokemonBattler]
# @param launcher [PFM::PokemonBattler, nil] potential launcher of a move
# @param skill [Battle::Move, nil] potential move used
# @return [:prevent, nil]
def check_groggy_prevention(status, target, launcher, skill)
return if status != :custom_groggy || target.can_be_groggy?

return prevent_change do
scene.display_message_and_wait(parse_text_with_pokemon(19, 285, target)) if skill.nil? || skill.status?
end
end
end
Battle::Logic::StatusChangeHandler.prepend(GroggyPrevention)

super exécute d'abord toutes les vérifications de prévention officielles ; result ||= ajoute ensuite la sienne uniquement si aucune n'a déjà bloqué le statut, en conservant exactement la structure que le moteur utilise pour ses propres statuts. La fonction dédiée check_groggy_prevention se lit : si la demande concerne son statut et que la cible ne peut pas le recevoir, on bloque le changement et on affiche le texte de prévention. parse_text_with_pokemon(19, 285, target) lit la ligne 285 du fichier de texte 100019, que l'on ajoute via Studio.

Corriger le message de guérison (optionnel)

Quand un statut est soigné en combat (par une attaque, un objet ou un talent), le handler le retire de façon générique, mais le message affiché est choisi par sa méthode privée cure_message_id. Cette méthode ne connaît que les statuts officiels et retombe sur la ligne « réveil » pour tout le reste : un statut personnalisé soigné afficherait donc le mauvais texte. Si le statut peut être soigné en combat, on prepend une surcharge qui renvoie sa propre ligne de message :

module GroggyCureMessage
private

# @param target [PFM::PokemonBattler]
# @return [Integer] line of text file 100019
def cure_message_id(target)
return 330 if target.groggy?

return super
end
end
Battle::Logic::StatusChangeHandler.prepend(GroggyCureMessage)

cure_message_id s'exécute avant que le statut soit retiré, donc target.groggy? est encore vrai à ce moment. On renvoie la ligne de son texte de guérison (ajoutée via Studio dans le fichier 100019) pour son statut, et on délègue à super pour tous les autres. La guérison elle-même fonctionne sans cette surcharge ; seul le message affiché en a besoin.

Ajouter un bonus de capture (optionnel)

Dans les jeux principaux, un Pokémon sous statut est plus facile à capturer. Si le statut doit accorder le même bonus, on étend STATUS_MODIFIER sur Battle::Logic::CatchHandler :

module Battle
class Logic
class CatchHandler < ChangeHandlerBase
STATUS_MODIFIER[:custom_groggy] = 1.5
end
end
end

La valeur est un multiplicateur appliqué au taux de capture. Pour référence, les statuts officiels utilisent 1.5 (poison, brûlure, paralysie) jusqu'à 2.5 (sommeil, gel). Toute valeur positive fonctionne : un multiplicateur inférieur à 1 ferait baisser le taux de capture.

Créer la classe d'effet du statut

Le comportement d'un statut en combat vit dans une sous-classe de Battle::Effects::Status. On ajoute d'abord une méthode de lecture à la classe parente pour que le moteur puisse reconnaître le statut depuis un effet :

module Battle
module Effects
class Status < EffectBase
# Tell if the status effect is groggy
# @return [Boolean]
def groggy?
@status == :custom_groggy
end
end
end
end

On crée ensuite la classe d'effet elle-même et on l'enregistre :

module Battle
module Effects
class Status
class Groggy < Status
# Prevent groggy from being applied twice
# @param handler [Battle::Logic::StatusChangeHandler]
# @param status [Symbol] :poison, :toxic, :confusion, :sleep, :freeze, :paralysis, :burn, :flinch, :cure
# @param target [PFM::PokemonBattler]
# @param launcher [PFM::PokemonBattler, nil] potential launcher of a move
# @param skill [Battle::Move, nil] potential move used
# @return [:prevent, nil] :prevent if the status cannot be applied
def on_status_prevention(handler, status, target, launcher, skill)
return if target != self.target
return if status != :custom_groggy

return handler.prevent_change do
handler.scene.display_message_and_wait(parse_text_with_pokemon(19, 282, target))
end
end

# Name of the effect
# @return [Symbol]
def name
:custom_groggy
end
end

register(:custom_groggy, Groggy)
end
end
end
  • On nomme la classe en PascalCase (Groggy, MyCustomStatus).
  • on_status_prevention s'exécute tant que le Pokémon porte déjà le statut : ici, elle bloque sa réapplication et affiche le texte « déjà sous statut » à la ligne 282 du fichier 100019.
  • register(:custom_groggy, Groggy) lie le symbole à la classe via la factory.

À partir de là, le statut est pleinement reconnu par le moteur. Pour lui donner de vrais effets (dégâts par tour, changements de stats, etc.), on surcharge les hooks d'EffectBase. Les statuts existants dans 5 Battle/06 Effects/03 Status Effects/ (rechercher < Status, ou < EffectBase pour l'ensemble complet des effets surchargeables) sont la référence de ce qui est possible.

Ajouter l'icône du statut

Éditer le fichier graphique

Les statuts officiels ont une icône sur l'interface de combat, et le sien le peut aussi. Les icônes vivent dans graphics/interface, une planche par langue :

  • statutsen.png (anglais, le repli par défaut)
  • statutsfr.png (français)
  • statutses.png (espagnol)

Si la langue du jeu n'a pas de planche, on crée statuts[code].png (par exemple statutsde.png pour l'allemand, avec le code de langue défini dans Studio). On édite la planche de sa langue, ou l'anglaise par défaut.

Chaque icône occupe une bande de 10 pixels de haut, ordonnée par ID de statut. Pour ajouter la sienne (toutes les coordonnées se mesurent depuis le coin supérieur gauche) :

  • On étend la hauteur de l'image à 10 * (ID + 1) pixels. Avec l'ID 20, la planche fait 10 * 21 = 210 pixels de haut.
  • On dessine son icône en X = 0, Y = 10 * ID. Avec l'ID 20, cela donne Y = 200.
  • On répète pour chaque planche de langue maintenue.

Un espace vide entre son icône et la précédente est normal quand l'ID n'est pas contigu ; c'est sans conséquence.

Déclarer le nombre d'icônes dans le code

Enfin, on indique à la classe de sprite combien de bandes de statut la planche contient désormais. UI::StatusSprite expose une constante STATE_COUNT ; on la surcharge depuis un script personnalisé avec son ID le plus haut plus un :

module UI
class StatusSprite < SpriteSheet
remove_const :STATE_COUNT
# Number of status icons in the sheet
STATE_COUNT = 21
end
end

Avec un ID maximal de 20, STATE_COUNT vaut 21. On met cette valeur à jour chaque fois qu'on ajoute un autre statut personnalisé avec un ID plus élevé.

Récapitulatif des fichiers

FichierAction
Studio -> AttaquesDéfinir le statut personnalisé sur chaque attaque qui doit l'infliger
Data/configs/states.jsonDéclarer l'ID du statut
Studio -> Textes de combat (fichier 100019)Ajouter les messages d'application, de prévention et de guérison (optionnel)
mon-projet/scripts/001 PokemonStatus.rbAjouter groggy?, status_groggy, can_be_groggy? à PFM::Pokemon
mon-projet/scripts/002 StatusChange.rbEnregistrer dans STATUS_APPLY_METHODS, les messages, la prévention
mon-projet/scripts/003 CatchHandler.rbAjouter à STATUS_MODIFIER (bonus de capture optionnel)
mon-projet/scripts/004 StatusEffect.rbAjouter la méthode de lecture parente et créer la classe d'effet
graphics/interface/statuts[lang].pngAjouter l'icône du statut
mon-projet/scripts/005 StatusSprite.rbMettre à jour STATE_COUNT

Conclusion

  • On nomme le statut dans Studio et on l'assigne aux attaques concernées ; le préfixe Custom_ devient le symbole :custom_groggy.
  • On déclare son ID dans states.json, bien au-dessus des officiels.
  • On reproduit les méthodes de lecture et d'application officielles sur PFM::Pokemon.
  • On l'enregistre dans le StatusChangeHandler (méthode d'application, messages, prévention) et, en option, dans le CatchHandler pour un bonus de capture.
  • On crée la classe d'effet avec register, puis on code son comportement en surchargeant les hooks d'EffectBase.
  • On ajoute l'icône aux planches de statut et on incrémente STATE_COUNT.
  • Les statuts existants dans 5 Battle/06 Effects/03 Status Effects/ sont la référence pour coder des effets plus riches.