Registrarse

[Scripting] Tutorial de Scripting para BDSP

Blup

Ribbit ribbit
Encargado de Switch
Tutorial de Scripting para BDSP

Introducción

¡Hola! Soy Blup. Este año he descubierto las posibilidades del ROM hacking de BDSP, una base relativamente reciente y poco conocida hasta ahora.

He estado trabajando, aprendiendo e investigando intensamente sobre esta nueva base.
En este tiempo, he traducido el ROM hack Pokémon Luminescent Platinum al español, también he creado múltiples parches como un parche de accesibilidad para ayudar a jugadores ciegos a disfrutar del juego, otro para restaurar los equipos originales de BDSP y Platino, un parche que añade un Centro Pokémon portátil en forma de objeto, y mucho más.
Todo mi trabajo se puede encontrar en Nexus Mods: https://next.nexusmods.com/profile/Blupblurp/mods?gameId=5055
Actualmente colaboro como scripter para el próximo proyecto de Team Lumi: Pokémon Re:Illuminated Platinum.

He decidido crear una serie de tutoriales para demostrar que es mucho más sencillo de lo que puede parecer obtener resultados increíbles al hacer un ROM hack utilizando un juego de octava generación como es BDSP, y la gran cantidad de posibilidades que ofrece esta base, que en mi opinión está prácticamente a la par con el ROM hacking de GBA (salvo en temas de 3D, por supuesto).

Mi intención es expandir este tutorial progresivamente hasta cubrir todo lo que he aprendido. Se agradece cualquier recomendación y se aceptan sugerencias sobre aspectos del scripting que puedan interesar más a la comunidad.

Más adelante también crearé otro tutorial para enseñar cómo editar la información del juego (entrenadores, objetos, Pokémon, movimientos... ¡todo lo que podáis imaginar!), pero he decidido empezar con el scripting, ya que considero que es lo más interesante.

Para contactar conmigo, podéis comentar en este post o uniros a mi servidor de Discord sobre modding de BDSP, donde puedo resolver cualquier duda y publico actualizaciones sobre mis parches: https://discord.gg/5Qwz85EvC3

Muchas gracias a Team Lumi por enseñarme la mayoría de lo que he aprendido.


Índice del tutorial
  • Introducción
  • Cómo preparar el entorno de desarrollo
  • Entendiendo los distintos archivos y la estructura de los scripts
  • PlaceDatas (Overworlds)
  • Flags, inverse flags, sysflags y works
  • Control de flujo: JUMP, CALL, IFVAL, IF_FLAG, SWITCH
  • StopDatas (Triggers)
  • Comandos de movimiento y animaciones
  • Comandos de Macros y archivos de idioma
Próximamente
  • Map Warps
  • Lista completa de comandos
  • ...

Introducción al Scripting

Los scripts son los encargados de gestionar el diálogo en el juego, los eventos, el movimiento de NPCs, las batallas contra entrenadores y mucho más.
El sistema de scripting de BDSP es muy similar al de Pokémon Platino para Nintendo DS. Además, utiliza un lenguaje propietario que es bastante sencillo de aprender.

Podéis encontrar más documentación e información sobre los comandos en:

Cómo preparar el entorno de desarrollo

Configurando VS Code con las extensiones para ev_as
  1. Descarga VS Code
  2. Busca "BDSP Tools" en las extensiones e instálalo
Descargar ev_as y comandos personalizados para trabajar con Lumi

Clona mi fork de ev-as y sigue las instrucciones para configurarlo en: https://github.com/BlupBlurp/multi-language-ev-as
Si no tienes Git instalado, puedes simplemente descargar el código en este enlace: https://github.com/BlupBlurp/multi-language-ev-as/archive/refs/heads/main.zip

La carpeta del proyecto debería quedar de la siguiente forma:

Código:
├───bin
├───Dpr
├───parsed
├───scripts
└───src
    └───ev_as.py
    └───ev_parse.py
Obteniendo el archivo ev_script

Este tutorial asume que el usuario ya posee su propia copia de Brilliant Diamond o Shining Pearl, junto con la actualización 1.3.0.

Puedes omitir este paso si quieres usar Luminescent Platinum (https://www.nexusmods.com/pokemonbdsp/mods/1) (muy recomendado) como base para tu proyecto en lugar de BDSP vanilla.
  1. Crea una carpeta llamada "romfs"
  2. Ve a Ryujinx, haz clic derecho en el juego
  3. En la parte inferior, pulsa en "Extract Data > RomFS"
  4. Elige la carpeta que acabas de crear como destino
Una vez hayas extraído la carpeta romfs o descargado Luminescent Platinum, ve a romfs\Data\StreamingAssets\AssetAssistant\Dpr y copia el archivo ev_script a la carpeta "Dpr" de tu proyecto.

Extraer scripts

En la consola, ejecuta python scr/ev_parse.py. Esto debería extraer todos los archivos de scripts a la carpeta "parsed".
Mueve todos estos archivos a la carpeta "scripts".

Compilar scripts

Una vez hayas terminado tus cambios o quieras testear, utiliza python scr/ev_as.py. Esto debería crear un nuevo archivo ev_script dentro de la carpeta "bin".
  • Si has usado Lumi como base, reemplaza el archivo ev_script que usaste originalmente por este, y tus cambios aparecerán en el juego.
  • Si has usado BDSP vanilla como base, deberás crear tu propia carpeta para tu mod, utilizando la misma ruta: romfs\Data\StreamingAssets\AssetAssistant\Dpr
Muy recomendable para cualquier proyecto serio: usar Git y GitHub.
Entendiendo los distintos archivos y la estructura de los scripts

Estructura y sintaxis de un script

Dentro de cada archivo encontraréis múltiples funciones (también llamadas scripts, aunque puede resultar confuso llamar tanto a los archivos como a su contenido por el mismo nombre). Todas siguen la misma estructura:
  • Un nombre (también conocido como label) marcado en azul que identifica la función
  • Comandos (es importante que cada función siempre acabe con `_END()` o `_RET()`. Explicación más adelante.)
  • Comentarios. Siempre comienzan por ";", y no afecta el código. Útiles para documentar los scripts.



Convenciones de nomenclatura

Puedes elegir el nombre que quieras para tus funciones, siempre y cuando sean únicos EN TODO EL PROYECTO.
Dos funciones no pueden llamarse de la misma forma, incluso aunque formen parte de archivos distintos, ya que el juego trata todo como un mismo archivo.

Normalmente se utilizan las siguientes reglas:
  • Los nombres siempre empiezan por "ev_" (a excepción de animaciones, stopdatas o map scripts, que se tratarán más adelante)
  • Seguido del identificador del mapa (el mismo que el nombre del archivo)
  • Finalmente una palabra o varias para identificar qué hace la función
  • Todo separado con guiones bajos "_"

Scripts de cada mapa

Los distintos archivos están nombrados usando el identificador del mapa al que están asociados. Podéis encontrar una lista de todos los mapas y sus identificadores en: https://luminescent.team/rom-hacking/dictionary/zones (en la última columna llamada "Zone code").

Tip: Puedes usar "Ctrl + P" en VS Code para buscar archivos rápidamente.
Map scripts

Los map scripts son scripts especiales que se pueden identificar porque su nombre empieza por "sp_" seguido del identificador del mapa. Estos scripts contienen funciones que son llamadas cuando se accede al mapa.

Normalmente encontraréis cuatro tipos:
  • INIT
  • OBJ
  • SCENE
  • FLAG
Todas estas funciones son llamadas cuando se accede al mapa, en ese orden específico.

Scripts especiales

Algunos scripts no están relacionados con un mapa específico. Los más importantes son:
  • common_scr: Contiene funciones que son llamadas por distintos scripts, utilizado para evitar repetir funciones comunes en cada script
  • door: Contiene las funciones que se ejecutan cuando el jugador entra por una puerta
  • init_scr: Este script se ejecuta al empezar una nueva partida

PlaceDatas (NPCs y otras entidades del mapa)

Introducción

PlaceDatas es como se conoce a todas las entidades de un mapa: NPCs, objetos, arbustos de bayas, etc. (conocidos como "Overworlds" en otras bases).

La información de estos objetos se encuentra en los archivos PlaceData de cada mapa, dentro del archivo masterdatas, en: \romfs\Data\StreamingAssets\AssetAssistant\Dpr

Extracción de archivos

Para poder extraer los archivos, es necesario usar la herramienta BDSP Repacker, que podéis descargar aquí: https://github.com/Ai0796/BDSP-Repacker
  1. Coloca el archivo masterdatas en "AssetFolder"
  2. Usa "unpack.exe"
  3. Dentro de la carpeta AssetFolder debería aparecer una nueva carpeta llamada "masterdatas_Export"
  4. Copia esta carpeta a la carpeta de tu proyecto

Una vez que hayas realizado los cambios que desees:
  1. Copia de nuevo la carpeta "masterdatas_export"
  2. Llévala a la carpeta AssetFolder de BDSP repacker
  3. Reemplaza los archivos cuando te lo indique
  4. Ejecuta "Repack.exe"
  5. En la carpeta "EditedAssets" verás un nuevo archivo masterdatas que puedes colocar en tu mod

Estructura de archivos PlaceData

Los archivos PlaceData siempre se llaman "PlaceData_" seguido del mismo identificador de mapa que se usa en los scripts.

Dentro, lo que nos importa es el array "Data". Aquí se encuentran todos los objetos de ese mapa, todos con las mismas propiedades:



Propiedades principales
  • ID: Nombre del objeto, debe ser único, en mayúsculas. Normalmente empieza con el nombre del mapa, seguido de una palabra descriptiva
  • zoneID: Número del mapa en el que se encuentra el objeto, corresponde a la primera columna de la tabla de zonas
  • TrainerID: Identificador del entrenador, si el NPC es un entrenador. Si no, siempre es 0 (solo se usa para entrenadores que pueden empezar una batalla al verte, no para batallas scripteadas como líderes de gimnasio)
  • ObjectGraphicIndex (OGI): Determina el modelo que se usará para la entidad (personaje, Pokémon, Pokéball, etc.)
    Para utilizar modelos de Pokémon, se usa: numeroDex/00/00. Los ceros hacen referencia a la forma del Pokémon (si tiene formas alternativas, su género, si es shiny, etc. Por ejemplo, "1510000" sería Mew.
    Podeis encontrar una lista en: https://bdsp-modding.wiki/index.php/Visuals#Object_Graphics
  • ColorIndex: Algunos ObjectGraphicIndex pueden tener variantes, como distintos colores de piel o pelo. Si se usa -1, copiará al jugador
  • Position: La posición del objeto en el mapa. 0,0 es siempre arriba a la izquierda
  • HeightLayer: La posición Z del objeto. Importante, por ejemplo, si se encuentra encima de una montaña
  • HeightIgnore: Cuando es 1, te permite interactuar con el objeto aunque no esté a tu misma altura
  • Size: Normalmente es siempre 0,0. Solo se pueden modificar estos valores si el OGI es un Pokémon u otro AssetBundle
  • Rotation: La rotación del objeto (imagen debajo mostrando el ángulo de cada dirección)


Propiedades de movimiento
  • MoveLimit: Algunos MoveCodes permiten al NPC andar por sí mismo; estos valores limitan cuánto puede moverse en cada dirección
  • MoveCode: Determina cómo el objeto se va a mover
Código:
MV_DMY = 0          MV_RTLUDR = 29
MV_PLAYER = 1       MV_RTUDRL = 30
MV_DIR_RND = 2      MV_RTRLUD = 31
MV_RND = 3          MV_RTDRLU = 32
MV_RND_V = 4        MV_RTRUDL = 33
MV_RND_H = 5        MV_RTUDLR = 34
MV_RND_UL = 6       MV_RTLRUD = 35
MV_RND_UR = 7       MV_RTDLRU = 36
MV_RND_DL = 8       MV_RTUL = 37
MV_RND_DR = 9       MV_RTDR = 38
MV_RND_UDL = 10     MV_RTLD = 39
MV_RND_UDR = 11     MV_RTRU = 40
MV_RND_ULR = 12     MV_RTUR = 41
MV_RND_DLR = 13     MV_RTDL = 42
MV_UP = 14          MV_RTLU = 43
MV_DOWN = 15        MV_RTRD = 44
MV_LEFT = 16        MV_RND_UD = 45
MV_RIGHT = 17       MV_RND_LR = 46
MV_SPIN_L = 18      MV_SEED = 47
MV_SPIN_R = 19      MV_PAIR = 48
MV_RT2 = 20         MV_REWAR = 49
MV_RTURLD = 21      MV_TR_PAIR = 50
MV_RTRLDU = 22      MV_HIDE_SNOW = 51
MV_RTDURL = 23      MV_HIDE_SAND = 52
MV_RTLDUR = 24      MV_HIDE_GRND = 53
MV_RTULRD = 25      MV_HIDE_KUSA = 54
MV_RTLRDU = 26      MV_CODE_MAX = 55
MV_RTDULR = 27      MV_CODE_NOT = 255
MV_RTRDUL = 28
  • MoveParam0, MoveParam1, MoveParam2: Algunos MoveCodes utilizan estos parámetros. Por ejemplo, los entrenadores necesitan un MoveCode de 14-17 y MoveParam0 indica a cuántos tiles de distancia pueden ver al jugador

Propiedades de interacción
  • TalkLabel: La función que se ejecutará cuando el jugador interactúe con el objeto
  • ContactLabel: La función que se ejecutará cuando el jugador choque contra el objeto
  • Work: Este valor es 4000 si el objeto es siempre visible. Otros valores de flags pueden ser usados para hacer que el objeto aparezca solo en determinadas ocasiones, o hacerlo desaparecer al final de un evento. Más información en el apartado de flags
  • Dowsing: Si el valor es 1 o 2, determina a qué distancia se puede detectar un objeto oculto
  • LoadFirst: Da prioridad al PlaceData para cargarse antes que otros. Normalmente 0
  • DoNotLoad: Siempre 4000

Propiedades de rango de interacción
  • TalkToRange: Distancia desde la que se puede interactuar con un objeto. Siempre se añade 0.25 a la cantidad de tiles. Normalmente 1.25
  • TalkToSize: Utilizando valores superiores a 1, expande la cantidad de tiles que forman el área desde la que se puede interactuar (sin cambiar nada visualmente). Cada tile se podrá interactuar desde la distancia determinada por TalkToRange. Normalmente utilizado en televisiones, que usan un único PlaceData y ocupan dos tiles de ancho
  • TalkBit: Indica las direcciones desde las que se puede interactuar con el objeto
Código:
1 (0001): Solo desde arriba
2 (0010): Solo desde abajo
3 (0011): Desde arriba y desde abajo
4 (0100): Solo desde la derecha
5 (0101): Arriba y derecha
6 (0110): Abajo y derecha
7 (0111): Arriba, abajo y derecha
8 (1000): Solo desde la izquierda
9 (1001): Arriba e izquierda
10 (1010): Abajo e izquierda
11 (1011): Arriba, abajo e izquierda
12 (1100): Derecha e izquierda
13 (1101): Arriba, derecha e izquierda
14 (1110): Abajo, derecha e izquierda
15 (1111): Todas las direcciones

Archivos de área

Algunos mapas están agrupados en "Áreas", en vez de tener archivos PlaceData individuales. Por ejemplo: "PlaceData_A01.json".

Estos archivos contienen múltiples mapas exteriores en uno, y sus objetos se distinguen porque tienen distintos zoneIDs.

Para saber a qué área corresponde cada mapa, podéis consultar la columna "File Path" de la tabla: https://luminescent.team/rom-hacking/dictionary/zones

Flags, inverse flags, sysflags y works

Introducción

En el scripting de BDSP, existen cuatro tipos de variables que nos permiten gestionar el estado del juego:
  • Flags: Variables booleanas que pueden ser verdadero o falso (set o unset). Usadas en la mayoría de eventos para marcar cuándo un script ha sido completado, o que decisiones ha tomado el jugador.
  • Inverse Flags: Igual que las flags, pero están activadas por defecto.
  • SysFlags: Flags del sistema, utilizadas para marcar información importante, como si una medalla ha sido obtenida.
  • Works: Variables que pueden contener cualquier valor numérico, ya sea decimal o entero, o incluso texto. Utilizadas para guardar información que necesita más complejidad que una flag.
Podéis encontrar una lista de las variables utilizadas por el juego (BDSP vanilla, no incluye Luminescent Platinum) en: https://bdsp-modding.wiki/index.php/Flags

Flags

Las flags se pueden reconocer por un "#" seguido de un número, por ejemplo #2450. Las flags de la 1 a la 1756 son usadas por el juego y también pueden aparecer utilizando un nombre en vez de un número, por ejemplo #FE_C06R0401_BIGMAN_TALK.

La flag #4000 es especial, ya que es una flag que siempre está desactivada. Se utiliza, por ejemplo, en los PlaceDatas que siempre están visibles.

El resto de flags deberían estar disponibles, pero es importante siempre comprobar que el nuevo número que vayas a utilizar no esté ya en uso.

Cómo verificar si una flag está libre
  1. Utiliza la función de buscar en todo el proyecto de VSCode (Ctrl+Shift+F)
  2. Busca en todos los scripts si la flag ya está en uso: #numero
  3. Comprueba también si se utiliza en algún PlaceData: "Work": numero
  4. Si la búsqueda no devuelve ningún resultado, entonces la flag está libre
  5. Si aparece solo en los scripts door.ev y/o init_scr.ev, entonces la flag seguramente sea una inverse flag

Comandos para modificar flags
  • FLAG_SET(#flag): Activa la flag
  • FLAG_RESET(#flag): Desactiva la flag
Inverse Flags

Las inverse flags son flags especiales que están activadas por defecto, en vez de desactivadas. Estas flags están definidas en los scripts door.ev y/o init_scr.ev.

Cómo encontrar las inverse flags
  1. Dirígete a door.ev
  2. Busca la función ev_healthcheck_init_inverse_flags
  3. Allí verás todos los números que son inverse flags
  4. También puedes comprobar init_scr.ev, pero no siempre son las mismas
  5. Puedes añadir cualquier flag que no esté en la lista y no esté utilizada para convertirla en una inverse flag
Estas flags especiales son principalmente utilizadas para PlaceDatas que deben estar desactivados por defecto, y se activarán como parte de un evento.

SysFlags

Las SysFlags son flags importantes para los sistemas del juego. Se pueden identificar como $numero o $nombre.

Por ejemplo, $BADGE_ID_C03 guarda la información sobre si la medalla de Ciudad Pirita ha sido obtenida.

Comandos para modificar SysFlags
  • _SET_SYS_FLAG($flag): Activa la sysflag
  • _RESET_SYS_FLAG($flag): Desactiva la sysflag
Works

Los works pueden contener multitud de valores, y se identifican como @número.
Los works desde 0 hasta 439 son utilizados por el juego.

Works temporales
Algunos works tienen la función de ser utilizados temporalmente, para cuando necesitas conservar un valor dentro de una función para usarlo más tarde, pero no necesitas conservarlo a largo plazo:
  • @LOCALWORK0 hasta @LOCALWORK31
  • @SCWK_TEMP0 hasta @SCWK_TEMP3
  • @SCWK_ANSWER: Normalmente utilizado en comandos que devuelven un valor
Cómo verificar si un work está libre
  1. Utiliza la función de búsqueda de VSCode
  2. Busca @numero en todos los archivos
  3. Busca "Work": numero en archivos StopData
Comandos para modificar works
  • _LDWK([USER=45027]@Work[/USER], value): Establece el valor de un work
  • _ADD_WK([USER=45027]@Work[/USER], value): Añade el valor proporcionado al work
  • _SUB_WK([USER=45027]@Work[/USER], value): Resta el valor proporcionado al work
Control de flujo: JUMP, CALL, IFVAL, IF_FLAG, SWITCH

Introducción

Una vez has entendido el concepto de works y flags, es hora de introducir algunos de los comandos más importantes para la lógica del scripting.

Estos comandos te permiten:
  • Saltar o llamar a otros scripts
  • Comprobar el valor de una flag o work para hacer saltos condicionales
  • Crear eventos complejos que cambian en función de las decisiones del jugador, de su progreso, de su posición, etc.
JUMP

El comando _JUMP('label-del-script') te permite saltar a otra función.

Importante: Cuando se salta a otra función de esta forma, los comandos que se encuentren después de JUMP nunca serán ejecutados, ya que la ejecución ya ha saltado a una función distinta.
CALL

El comando _CALL('label-del-script') llama a otra función. A diferencia de JUMP, cuando todos los comandos de esa función se hayan ejecutado:
  • Si la función acaba con _RET() en lugar de _END(), el script volverá a la función original del comando CALL
  • Seguirá ejecutando los comandos posteriores al CALL

Nota: Si una función utiliza CALL para saltar a otra, y esa otra utiliza JUMP para saltar a una tercera función que acaba en _RET(), la ejecución también volverá a la primera función original donde se encuentra el comando CALL.
IFVAL

Los comandos _IFVAL_JUMP([USER=45027]@Work[/USER], 'comparador', valor, 'label-del-script') y _IFVAL_CALL permiten comprobar si el valor de un work cumple una condición, y si es así, saltan o llaman a otro script.

Comparadores disponibles
  • EQ: El valor del work y el segundo valor son iguales
  • NE: Los valores son distintos
  • GT: El primer valor es mayor que el segundo
  • GE: El primer valor es mayor o igual que el segundo
  • LT: El primer valor es menor que el segundo
  • LE: El primer valor es menor o igual que el segundo

IF_FLAG

Similar a IFVAL, estos comandos comprueban si una flag está activada (set, on) o desactivada (reset, off), y si es así, saltan o llaman a otro script:
  • _IF_FLAGON_JUMP(#flag, 'label-del-script')
  • _IF_FLAGOFF_JUMP(#flag, 'label-del-script')
  • _IF_FLAGON_CALL(#flag, 'label-del-script')
  • _IF_FLAGOFF_CALL(#flag, 'label-del-script')
SWITCH

El comando _SWITCH([USER=45027]@Work[/USER]) permite hacer múltiples comprobaciones de igualdad referidas a un mismo work más fácilmente que usando IFVAL.

Cómo utilizarlo
  1. Primero se indica el work con el comando _SWITCH([USER=45027]@Work[/USER])
  2. A continuación se utilizan los comandos _CASE_JUMP(valor, 'label-del-script') y _CASE_CALL(valor, 'label-del-script')
  3. Si el work indicado y el valor son iguales, se saltará o llamará a la función
StopDatas (Triggers)

Introducción

Los StopDatas, también conocidos como "triggers" en otras bases, actúan como un rango de tiles invisibles que accionan una función cuando el jugador entra en dicho rango.

Están definidos en los archivos StopData de masterdatas, al igual que los PlaceDatas. Se pueden identificar porque su nombre siempre empieza por "StopData_" seguido del identificador del mapa.



Estructura de archivos StopData

Al igual que los PlaceData, los StopDatas tienen distintas propiedades importantes:

Propiedades principales
  • ID: Nombre único del StopData. Generalmente siempre comienza por "SCRID_POS", seguido del identificador del mapa, y a continuación una palabra descriptiva
  • Position: Determina la posición del StopData en el mapa
  • HeightLayer: Determina la altura a la que se encuentra en el mapa
  • Size: Determina el tamaño del área. Es importante tener en cuenta que el tile inicial se encuentra siempre arriba a la izquierda, por lo que el tamaño se aumenta hacia abajo y hacia la derecha
Propiedades de activación
  • ContactLabel: Función que será llamada cuando el jugador entre en el área. A diferencia de las funciones normales, su nombre empieza por "pos_" en vez de "ev_"
  • Param: Valor que el work proporcionado deberá tener para que el StopData se active cuando el jugador entra en su rango. Si el valor es cualquier otro, la función no será llamada
  • Work: Work (en número) que el StopData comprobará contra el "Param"

Comandos de movimiento y animaciones

Introducción

Las funciones de animación son funciones especiales que permiten modificar el estado del jugador o PlaceDatas. Con estas funciones puedes:
  • Mostrar burbujas de emojis sobre los personajes
  • Hacer que los NPCs caminen una cantidad específica de tiles
  • Reproducir animaciones concretas
  • Cambiar la dirección hacia la que mira un personaje
  • Y mucho más
Convenciones para funciones de animación

Las funciones de animación siguen reglas específicas:
  • Siempre empiezan su nombre por anm_ en vez de ev_
  • Seguido del identificador del mapa y palabras descriptivas
  • Siempre acaban con el comando _ACMD_END(), en vez de _END()
Importante: Los comandos de animación solo pueden ser utilizados dentro de funciones de animación, estos comandos empiezan por AC_. Los comandos normales tampoco funcionarán dentro de funciones de animación.

Cómo utilizar funciones de animación

Llamar a una función de animación
Una vez que hayas creado tu función, puedes llamarla utilizando el comando _OBJ_ANIME('PlaceData-ID', 'label').
  • Este comando ejecutará la animación indicada en el PlaceData especificado
  • Si deseas que el jugador realice la función, el ID del PlaceData deberá ser 'HERO'

Sincronización de animaciones
El comando _OBJ_ANIME_WAIT() es muy útil para controlar el flujo:
  • Pausa la ejecución de la función principal hasta que la función de animación haya terminado
  • Diálogos u otras animaciones no ocurren hasta que la primera haya acabado
  • Sin este comando, la función principal continuará mientras la animación se ejecuta en paralelo

Nota: Las funciones de animación se ejecutan de forma asíncrona, por lo que es importante usar _OBJ_ANIME_WAIT() cuando necesites sincronización.
Comandos de animación principales

Comandos de dirección
Estos comandos cambian la dirección hacia la que mira un PlaceData:
  • _AC_DIR_U(tiempo): Mirar hacia arriba (Up)
  • _AC_DIR_D(tiempo): Mirar hacia abajo (Down)
  • _AC_DIR_L(tiempo): Mirar hacia la izquierda (Left)
  • _AC_DIR_R(tiempo): Mirar hacia la derecha (Right)
El parámetro tiempo indica la cantidad de frames que tarda en completar el giro.

Comandos de movimiento
Estos comandos hacen que el PlaceData se mueva una cantidad específica de tiles:
  • _AC_UP(tiles, frames): Moverse hacia arriba
  • _AC_DOWN(tiles, frames): Moverse hacia abajo
  • _AC_LEFT(tiles, frames): Moverse hacia la izquierda
  • _AC_RIGHT(tiles, frames): Moverse hacia la derecha
Importante: Los comandos de movimiento no cambian la dirección automáticamente. Si mueves a un PlaceData a la derecha sin hacer primero que mire hacia la derecha, se moverá hacia la derecha mientras sigue mirando hacia la dirección anterior.
Comandos de tiempo y espera
  • _AC_WAIT(frames): Espera una cantidad de frames antes de continuar con la ejecución
Comandos de reacciones
  • _AC_MARK_GYOE(): Hace que el PlaceData reaccione con una exclamación y sonido de exclamación
  • _AC_MARK_EMO(id): Hace que el PlaceData reaccione con un emoji específico
Para _AC_MARK_EMO, puedes encontrar la lista completa de emojis disponibles en: https://luminescent.team/rom-hacking/dictionary/chibi-emotions

Añadir sonido a las reacciones
Las reacciones de emoji no tienen sonido por defecto, pero puedes añadirlo:
  1. Usa el comando _PLAY_EMO_SE(id) en la función donde la animación es llamada
  2. NO en la función de animación misma
  3. Normalmente se coloca entre _OBJ_ANIME y _OBJ_ANIME_WAIT
Comandos de animaciones predefinidas
  • _AC_INDEX_ANIME(id): Reproduce una animación específica del PlaceData
  • _AC_INDEX_ANIME_WAIT(): Hace que la ejecución espere a que la animación termine
Puedes encontrar la lista completa de animaciones disponibles en: https://luminescent.team/rom-hacking/dictionary/chibi-animations

Comandos avanzados

Existen muchos más comandos de animación, como:
  • _AC_WORLD_X / _AC_WORLD_Z: Para hacer que el PlaceData se mueva a una posición específica
  • _AC_HERO_MATCH_X: Para hacer que un PlaceData se mueva hasta coincidir con la posición del jugador
  • Y muchos otros comandos especializados
Tip para aprender: La mejor forma de aprender y descubrir nuevos comandos es revisar scripts existentes que hagan cosas similares a lo que estás buscando. Muchos de estos comandos no están completamente documentados, pero puedes encontrar ejemplos prácticos en los scripts del juego.
Comandos de Macros y archivos de idioma

Introducción

Para editar los diálogos del juego o añadir nuevos, se utilizan "comandos de macros". Estos comandos te permiten:
  • Interactuar con los archivos de idioma sin modificarlos manualmente
  • Crear y editar diálogos directamente desde los scripts
Extraer los archivos de idioma

Paso 1: Obtener los archivos
El primer paso es extraer los archivos de idioma del juego:
  1. Ve a romfs\Data\StreamingAssets\AssetAssistant\Message
  2. Copia el idioma que desees:
    - "spanish" si quieres desarrollar en español
    - "english" si quieres desarrollar en inglés

Alternativa para usuarios de Lumi: Si usas Lumi como base en vez de BDSP vanilla, puedes descargar mi parche al español y copiar el archivo "spanish" desde: https://www.nexusmods.com/pokemonbdsp/mods/49
Paso 2: Extraer con BDSP-Repacker
  1. Lleva el archivo de idioma a la carpeta AssetFolder de BDSP-Repacker
  2. Al igual que con el archivo masterdatas, ejecuta unpack.exe
  3. En la carpeta AssetFolder aparecerá una nueva carpeta llamada:
    - spanish_Export o english_Export (según el idioma elegido)
  4. Copia esta carpeta y llévala a tu proyecto
Paso 3: Repack
Una vez hayas realizado cambios en los archivos de idioma, y quieras añadirlos al juego:
  1. Lleva la carpeta spanish_Export de tu proyecto a la carpeta AssetFolder de BDSP-Repacker
  2. Reemplaza los archivos cuando te lo indique
  3. Ejecuta repack.exe
  4. En la carpeta EditedAssets aparecerá tu nuevo archivo
  5. Copia este archivo y llevale a la misma ruta romfs\Data\StreamingAssets\AssetAssistant\Message en tu mod.

Estructura final del proyecto
La estructura debería quedar así:
Código:
├───AssetFolder
    └───spanish_Export
    └───masterdatas_Export
├───bin
├───Dpr
├───parsed
├───scripts
└───src
Comandos de Macros

Una vez que hayas preparado los archivos de idioma, puedes empezar a usar los comandos de macros.

Entendiendo los comandos de diálogo tradicionales
Habrás notado que los scripts utilizan comandos como:
_TALKMSG('dp_scenario1%66-msg_c03_girl3_02')

Este comando:
  • Muestra una caja de texto con el diálogo "66-msg_c03_girl3_02" del archivo "dp_scenario1"
  • Puedes encontrar el texto buscando el identificador en los archivos JSON exportados

Versión macro
La mayoría de los comandos de diálogo tienen una versión macro que permite editar el texto directamente desde el script:
_MACRO_TALKMSG('archivo', 'identificador', 'texto')

Funcionamiento de los comandos macro
  • Si el identificador NO existe en el archivo: ev-as creará una nueva entrada con el texto proporcionado
  • Si el diálogo YA existe: ev-as reemplazará el texto por el nuevo

Configuración de idioma: Por defecto, ev-as busca archivos en inglés. Para trabajar en español, usa: python src/ev_as.py --language spanish
Secuencias de escape

Para gestionar múltiples líneas, se pueden utilizar secuencias de escape en el texto:

Secuencias disponibles
  • \n: Salto de línea
  • \r: Salto de página
  • \f: Desplazamiento de página

Herramienta recomendada
Una herramienta esencial para escribir diálogos es BDSP Message Previewer: https://github.com/ProfBlack/BDSP-Message-Previewer/releases

Con esta herramienta puedes:
  • Ver exactamente los límites de cada línea
  • Elegir las secuencias de escape correctas
  • Copiar el texto formateado para usar en comandos de macro

Ejemplo práctico
_MACRO_TALKMSG('dp_scenario1', 'msg_c03_sergio_01', 'Psss, eh, chico.\n¿Quieres comprar Pokémon Naranja?')

Este comando:
  • Añade un nuevo diálogo al archivo 'dp_scenario1'
  • Con el identificador 'msg_c03_sergio_01'
  • El diálogo quedará separado en dos líneas

Convenciones de nomenclatura

Qué archivo elegir
Los diálogos pueden añadirse a cualquier archivo, pero para mantener organización:
  • Usa el mismo archivo que se use en el script en el que estás trabajando
  • Si por ejemplo, otros _TALKMSG usan dp_scenario1, úsalo para tus diálogos
  • Si usan dp_scenario2, usa ese en su lugar, etc.

Reglas para identificadores
Para elegir un nuevo identificador, sigue estas reglas:
  1. Empieza todos los identificadores por msg_
  2. Después, el identificador del mapa donde estás editando el script
  3. A continuación, el nombre de la función en la que estás trabajando
  4. Por último, un número que indica el orden del diálogo: _01, _02, etc.

Nota: Aunque muchos diálogos del juego empiezan por un número seguido de guión, no es necesario seguir esa convención.
Estructura de un diálogo

Todas las funciones que utilizan diálogos suelen seguir la misma estructura:

1. Comandos de inicio
Comienzan por uno de estos comandos:
  • _TALK_OBJ_START(): El jugador y el PlaceData se miran mutuamente
  • _TALK_OBJ_START_LOOK_NONE(): Ni el jugador ni el PlaceData cambian dirección
  • _TALK_OBJ_START_TURN_NOT(): Solo el PlaceData mira al jugador
Estos comandos también reproducen el sonido de interacción.

2. Comandos de diálogo
  • Usa comandos como _TALKMSG, macros o sus variantes
  • Todos los comandos de diálogo necesitan cerrarse con _TALK_CLOSE()
  • Si no se cierran, la caja de texto quedará abierta incluso al pulsar A
  • Añade tantos comandos de diálogo como quieras

3. Comando de finalización
  • Siempre que hayas iniciado con _TALK_OBJ_START o variantes
  • Debes acabar con _TALK_OBJ_END()
  • Este comando se suele colocar como penúltimo comando, justo antes de _END o _RET

Otros comandos de macro útiles

Opciones múltiples
_MACRO_ADD_CUSTUM_WIN_LABEL('archivo', 'identificador', 'texto', número)
  • Versión macro de _ADD_CUSTUM_WIN_LABEL
  • Añade opciones a un cuadro de opciones (típico "Sí/No")
  • Generalmente usa el archivo dp_options
  • Tras añadir las opciones que desees, usa _OPEN_CUSTUM_WIN(@SCWK_ANSWER) para abrir el cuadro
  • El número elegido se guarda en @SCWK_ANSWER
  • Usa comandos de control de flujo como _IFVAL para actuar según la elección

Diálogos simples
_MACRO_EASY_OBJ_MSG('archivo', 'id', 'texto')
  • Versión macro de _EASY_OBJ_MSG
  • Para funciones con un único comando de diálogo
  • Normalmente usado en funciones llamadas desde el TalkLabel de un PlaceData
  • Agrupa _TALK_OBJ_START y _TALK_OBJ_END en uno
  • Solo necesitas usar _EASY_OBJ_MSG y _END

Nota importante: Al extraer scripts con ev-parse, no verás comandos de macro, ya que ev-as los transforma en su contraparte tradicional. Por eso puede ser difícil buscar ejemplos en VSCode.
Tags para diálogos dinámicos

Los comandos de macro permiten utilizar variables llamadas "tags" que reciben información del script y la reflejan en el diálogo.

¿Qué permiten los tags?
  • Mostrar el nombre del jugador
  • Mostrar el nombre del rival
  • Mostrar nombres de Pokémon
  • Y otras variables dinámicas
Ejemplo básico con nombres
  1. Usa _PLAYER_NAME(número) o _RIVAL_NAME(número) antes del diálogo
  2. Asigna un número (0, 1, 2, etc.)
  3. En el comando de macro, escribe {número} donde quieras el nombre

Ejemplo práctico
Código:
_RIVAL_NAME(0)
_MACRO_TALKMSG('dp_scenario1', 'msg_c03_rival_01', 'El nombre del rival es: {0}')
En este ejemplo, {0} será sustituido por el nombre del rival.

Estado de desarrollo: Este es un tema algo complejo, y ev-as aún necesita ser actualizado para simplificar el proceso de añadir tags. La funcionalidad actual es básica, y a veces es necesario realizar cambios manualmente en los archivos de idioma.
 
Última edición:

Blup

Ribbit ribbit
Encargado de Switch
He añadido al tutorial las secciones de:
  • Flags, inverse flags, sysflags y works
  • Control de flujo: JUMP, CALL, IFVAL, IF_FLAG, SWITCH
  • StopDatas (Triggers)

La siguiente sección será "Comandos de movimiento y animaciones"
 

Micael_Alighieri

Emperador Kaktiácero
Redactor/a
Miembro de honor
Quién lo diría, haciendo tutoriales de programación tú también, ¡así es cómo empecé yo!

En fin, he visto que has aportado una colección de comandos y explicaciones bastante completa, así que enhorabuena. Eso sí, lo que entiendo es que algo tan abstracto como la programación requiere de una curva de aprendizaje un poco empinada, y según he visto en el último comentario del primer mensaje del tema, ya lo has dejado caer.

He visto otros de tus tutoriales y mostraste tanto ejemplos en vídeo, como imágenes, igual hacer pequeños vídeos cortos podría ayudar a hacer el tema más fácil de seguir. Otra idea, si quieres implementarla, es hacer que el post principal se vea menos voluminoso, por ejemplo, haciendo que puedas hacer click en el índice y que te conduzca a cada sección, y ocultándolas dentro de spoilers.

Gran aporte, saludos.
 

Blup

Ribbit ribbit
Encargado de Switch
Quién lo diría, haciendo tutoriales de programación tú también, ¡así es cómo empecé yo!

En fin, he visto que has aportado una colección de comandos y explicaciones bastante completa, así que enhorabuena. Eso sí, lo que entiendo es que algo tan abstracto como la programación requiere de una curva de aprendizaje un poco empinada, y según he visto en el último comentario del primer mensaje del tema, ya lo has dejado caer.

He visto otros de tus tutoriales y mostraste tanto ejemplos en vídeo, como imágenes, igual hacer pequeños vídeos cortos podría ayudar a hacer el tema más fácil de seguir.

Gran aporte, saludos.
¡Gracias de nuevo por tu comentario!
No creo que sea necesario hacer un video de ejemplo para cada sección/comando, individualmente son cosas muy sencillas.
Pero sí que podría mostrar los scripts del video de ejemplo del principio del tema, ya que incluye la mayoría de conceptos básicos.

No considero que el scripting de BDSP sea programar como tal, pero sí que es un concepto similar y puede ser abstracto.
Al final la mejor forma de aprender es empezar y probar poco a poco. Pero al ser un lenguaje basado en comandos que describen literalmente la acción que realizan, en el momento que tengas los conceptos básicos claros, creo que es muy fácil e intuitivo hacer cualquier cosa.

Mi intención con todos estos tutoriales es mostrar a la gente que el ROM hacking de BDSP es mucho más fácil de lo que parece y las posibilidades que tiene, para con suerte avivar un poco de motivación y que cada uno empiece a aprender y probar por su cuenta.
No son recursos completos incluyendo "todo lo que vas a necesitar saber", pero es suficiente para tener un comienzo en cada área.
 
Arriba