The wiki has been upgraded to MediaWiki 1.43. The wiki's theme is still being adapted to work with the new version, and may appear broken for the time being. --RanAS

es/Dynamic Xtreme ASM API

From SnesLab
Jump to: navigation, search
English Português Español 日本語

En este artículo se explica cómo usar las rutinas y macros de Dynamic Xtreme desde código ASM. Cada entrada indica para qué sirve la llamada, qué datos debes preparar y qué obtienes al ejecutarla, junto con un ejemplo.

Para aprender a organizar un sprite completo, consulta la guía de creación de sprites.

Funcionalidades necesarias para utilizar la API

Las rutinas, macros y variables disponibles dependen de las funcionalidades seleccionadas al instalar Dynamic Xtreme. Esta tabla indica qué debes habilitar para utilizar cada sistema:

Funcionalidad Rutinas y macros que permite utilizar Dependencias y detalles
GraphicsChange Transferencias a VRAM: TransferToVRAM y sus variantes FromAddr, Resource, WithLenght y Forced. Proporciona las cargas de gráficos. También es necesaria para DynamicPoses y PlayerFeatures.
DynamicPoses DefineDynamicSpaceConfig, DynamicPoseSpaceConfig, TakeDynamicRequest, DynamicRoutine, SetPropertyAndOffset, !Upload, !UploadWithoutPoseOffset y las macros generales GeneralUpload, Upload y StandardSpriteUpload. Requiere GraphicsChange. Para dibujar las poses obtenidas también necesitas DrawingSystem.
DrawingSystem !DXDraw, !DXDrawWithOffset y las macros generales Draw, StandardSpriteDraw y DrawStatic. Incluye las rutinas de dibujo y comprobación de tiles que utiliza el sistema. El dibujo de poses dinámicas también requiere DynamicPoses. DrawStatic puede dibujar poses estáticas sin habilitar el sistema de poses dinámicas.
PalettesChange AssignPalette, !PaletteAssignment, !PaletteAssignmentNoUpload, !ReplacePalette y sus macros generales; LoadPaletteIDAndAddress; las macros TransferPalette y las transferencias a CGRAM. Proporciona la asignación y carga de paletas. Para aplicar efectos también debes habilitar PalettesEffects.
PalettesEffects SetRGBBase, SetHSLBase, Mix, MixAndMerge, PaletteTransition, DoEffect y conversiones RGB/HSL, con sus variantes. También permite utilizar ConcatenateRGBPaletteEffectToGlobal y ConcatenateHSLPaletteEffectToGlobal, como aliases de sprites o macros generales. Requiere PalettesChange. Permite aplicar el efecto global mediante la asignación de paletas o TransferPalette.
PlayerFeatures Permite personalizar los gráficos y las paletas del jugador mediante las variables del jugador. No añade una familia de llamadas propia a las categorías anteriores. Requiere GraphicsChange y PalettesChange.
YoshiFeatures Permite personalizar los gráficos de Yoshi mediante las variables de Yoshi. Requiere PlayerFeatures, junto con sus dependencias.
Free7E2000 No añade llamadas a esta API. Libera y reorganiza el uso del espacio de RAM correspondiente. No es un requisito adicional para las macros de carga o dibujo. Se deshabilita en SA-1.
ControllerOptimization, FixedColorOptimization, KevinLMVRAMOptimization y StatusBarOptimization No añaden familias de llamadas a esta API. Modifican el funcionamiento interno de sus respectivos sistemas. No necesitas habilitarlas para obtener las macros de poses, dibujo, paletas o matemáticas.
Sin una funcionalidad adicional Mul, Div y sus variantes W y After.... Las macros de matemáticas se incluyen desde DXDefines.asm independientemente de las opciones anteriores.

Las macros de PPU se incluyen si está habilitado GraphicsChange o PalettesChange, pero utiliza las de VRAM con GraphicsChange y las de CGRAM con PalettesChange. Que Asar reconozca el nombre de una macro no significa que estén habilitadas las listas y variables que esa macro necesita.

Para cargar y dibujar poses dinámicas, habilita GraphicsChange, DynamicPoses y DrawingSystem. Si el sprite también carga paletas, añade PalettesChange; si utiliza efectos, añade PalettesEffects.

Integración con las herramientas

Contexto Archivos y llamadas
PIXI La instalación copia los defines generales a asm/ExtraDefines y las rutinas compartidas a routines. Para los aliases de sprites, incluye NormalSpriteDefines.asm, ClusterSpriteDefines.asm o ExtendedSpriteDefines.asm, según corresponda. Las diferencias entre tipos se indican en cada llamada.
UberASMTool La instalación enlaza ExtraDefines/DXDefines.asm desde other/macro_library.asm. Utiliza las macros generales y las rutinas del parche con sus parámetros; los aliases como !Upload pertenecen a los archivos de defines para sprites de PIXI.
GPS La instalación enlaza ExtraDefines/DXDefines.asm desde defines.asm. Utiliza las macros generales y las rutinas del parche, preparando sus entradas desde el código del bloque.

Estas integraciones se preparan para las herramientas configuradas durante la instalación. Si Asar no encuentra un nombre, comprueba la funcionalidad necesaria, los archivos incluidos y, si es un define generado, su escritura exacta en DXDefines.asm. Después de cambiar las funcionalidades o los recursos, reinstala Dynamic Xtreme y vuelve a ejecutar las herramientas que utilizan sus defines, como explica la guía de inicio rápido.

Variables y defines

DXDefines.asm reúne los nombres que utiliza Dynamic Xtreme para acceder a sus variables, configuraciones, recursos y rutinas. Algunos representan datos que cambian durante el juego; otros son valores fijos o se generan al instalar los recursos.

Los nombres de variables generales comienzan con DX_ y se escriben sin !, por ejemplo DX_Timer. Los defines como !DynamicPoseIDMySprite000 sí llevan !. Conserva la escritura exacta del nombre que aparece en el archivo.

Las variables disponibles dependen de las funciones habilitadas durante la instalación. No es necesario memorizar todas: busca la categoría del sistema con el que estás trabajando.

Variables generales

En las tablas, el tamaño indica cuántos bytes ocupa un valor. Para una tabla se indica también cuántos valores contiene. Las variables marcadas como internas las actualiza Dynamic Xtreme; normalmente se utilizan las rutinas de la API para trabajar con ellas.

Contadores y cantidad de datos por frame

Variable Tamaño Para qué sirve
DX_Timer 2 bytes Cuenta los frames en los que se ejecuta Dynamic Xtreme. Continúa durante la pausa y cuando se congela la acción. El sistema lo utiliza para saber cuándo se usó una pose por última vez.
DX_SyncTimer 2 bytes Cuenta los frames, pero se detiene cuando el juego está pausado o la acción está congelada. Puede utilizarse para animaciones que deban detenerse con el juego.
DX_Dynamic_CurrentDataSend 2 bytes Cantidad de bytes que ya se programaron para transferir durante el frame actual. La actualizan las rutinas de carga.
DX_Dynamic_MaxDataPerFrame 2 bytes Límite de bytes que las cargas normales pueden programar en un frame. Las variantes Forced pueden superarlo.

Poses cargadas en VRAM

Estas tablas permiten al sistema saber qué poses están cargadas, dónde están y cuáles siguen en uso. Son datos internos de la caché; para solicitar una pose utiliza !Upload o !TakeDynamicRequest.

Variable Tamaño Para qué sirve
DX_Dynamic_Pose_Length 1 byte Cantidad de poses registradas actualmente en la caché.
DX_Dynamic_Pose_HashSize 128 valores de 1 byte Ayuda a encontrar las poses por su ID.
DX_Dynamic_Pose_ID 128 valores de 2 bytes ID de cada pose registrada.
DX_Dynamic_Pose_Offset 128 valores de 1 byte Posición de los gráficos de cada pose en el espacio dinámico de VRAM, medida en bloques de 16×16.
DX_Dynamic_Pose_TimeLastUse 128 valores de 2 bytes Valor de DX_Timer de la última vez que se utilizó cada pose. Evita reemplazar gráficos que todavía se están mostrando.
DX_Dynamic_Tile_Size / DX_Dynamic_Tile_Pose 128 bytes compartidos Describen las partes libres u ocupadas de VRAM. Son dos nombres para el mismo espacio de memoria.
DX_Dynamic_Tile_Offset 128 valores de 1 byte Ayuda al sistema a recorrer las partes libres y ocupadas de VRAM.

Paletas y efecto global

Las tablas de 16 paletas utilizan el orden 0-F. En las tablas de valores de 2 bytes, la paleta 1 comienza en +2, la 2 en +4, y así sucesivamente.

Variable Tamaño Para qué sirve
DX_Dynamic_Palettes_GlobalBGEnable 1 byte Cada bit indica si una de las paletas 0-7 recibe el efecto global.
DX_Dynamic_Palettes_GlobalSPEnable 1 byte Cada bit indica si una de las paletas de sprites 8-F recibe el efecto global.
DX_Dynamic_Palettes_GlobalEffectID 2 bytes ID del efecto global que se quiere aplicar. El valor 0 indica que no se aplica un efecto global.
DX_Dynamic_Palettes_LastGlobalEffectID 2 bytes Último efecto global revisado por el sistema. Se utiliza para detectar cambios.
DX_Dynamic_Palettes_LastGlobalEffectIDPerPal 16 valores de 2 bytes Último efecto global calculado para cada paleta. $FFFF significa que aún no hay un resultado; $FFFE, que hay una actualización pendiente y se conserva el resultado anterior.
DX_Dynamic_Palettes_ID 16 valores de 2 bytes ID asociado a cada paleta. $FFFF indica que está libre; $FFFE la excluye de la selección automática.
DX_Dynamic_Palettes_Updated 16 valores de 1 byte Indica cuáles paletas ya se actualizaron durante el frame. Uso interno.
DX_Dynamic_Palettes_DisableTimer 16 valores de 1 byte Mientras sea distinto de 0, protege la paleta para que no sea reemplazada por otra asignación automática. Las llamadas que la utilizan vuelven a ponerlo en 2.
DX_Dynamic_Palettes_EffectEnabled 1 byte Registra qué paletas de sprites se utilizan con efectos. Uso interno del manejo de paletas.

Para reservar una paleta de sprites y evitar que la selección automática la utilice, su entrada de DX_Dynamic_Palettes_ID debe contener $FFFE. Haz la reserva antes de que los sprites comiencen a solicitar paletas.

Copias de colores y resultados de efectos

Variable Tamaño Para qué sirve
DX_PPU_CGRAM_PaletteCopy 512 bytes Copia de trabajo de las 256 entradas de color, con 2 bytes por color. Es la fuente de las variantes SetRGBBaseDefault y SetHSLBaseDefault.
DX_PPU_CGRAM_BaseRGBPalette 768 bytes Colores originales separados en rojo, verde y azul: 3 bytes por color.
DX_PPU_CGRAM_BaseHSLPalette 768 bytes Colores originales separados en tono, saturación y luminosidad: 3 bytes por color.
DX_PPU_CGRAM_LocalEffectBuffer 768 bytes Espacio de trabajo para el resultado de un efecto local antes de combinarlo con el global.
DX_PPU_CGRAM_LocalEffectID 16 valores de 2 bytes ID del efecto local aplicado a cada paleta.
DX_PPU_CGRAM_PaletteWriteMirror 512 bytes Colores resultantes en formato de SNES, con 2 bytes por color. Las variantes AndMergeDefault escriben aquí.
DX_PPU_CGRAM_BGBaseRGBPaletteLoaded / DX_PPU_CGRAM_SPBaseRGBPaletteLoaded 1 byte cada una Cada bit indica si ya se preparó la base RGB de una paleta de fondo o de sprites.
DX_PPU_CGRAM_BGBaseHSLPaletteLoaded / DX_PPU_CGRAM_SPBaseHSLPaletteLoaded 1 byte cada una Lo mismo para las bases HSL.
DX_PPU_CGRAM_BGEffectLoaded / DX_PPU_CGRAM_SPEffectLoaded 1 byte cada una Cada bit indica si ya hay un resultado del efecto para esa paleta.
DX_PPU_CGRAM_LastPlayerPal 2 bytes Dirección de la última paleta del jugador procesada. El sistema la compara para detectar cambios.

Escribir colores en una copia de RAM no los envía inmediatamente a CGRAM. Utiliza las rutinas de paleta o una transferencia para actualizar lo que se muestra en pantalla. Los indicadores de bases y efectos preparados los administra el sistema; no es necesario borrarlos antes de cada llamada.

Color fijo y primer color de la paleta

El color fijo es el color que SNES puede utilizar para efectos como sumas y restas de color. El color 0,0 es la primera entrada de CGRAM. Dynamic Xtreme permite aplicar el efecto global a ambos por separado.

Variable Tamaño Para qué sirve
DX_PPU_ColorEffect_Enable 1 byte Activa la participación en el efecto global: bit $01 para el color fijo y bit $02 para el color 0,0. $03 permite ambos.
DX_PPU_ColorEffect_BaseLoaded 1 byte Indica si se guardaron sus colores originales. Utiliza un bit por destino: $01 y $02.
DX_PPU_ColorEffect_RGBBaseLoaded / DX_PPU_ColorEffect_HSLBaseLoaded 1 byte cada una Indican si sus colores ya se prepararon en RGB o HSL, con los mismos bits.
DX_PPU_FixedColor_Mirror 2 bytes Copia del color fijo que utiliza la actualización habitual del juego.
DX_PPU_FixedColor_Base 2 bytes Color fijo original, antes de los efectos.
DX_PPU_FixedColor_RGBBase / DX_PPU_FixedColor_HSLBase 3 bytes cada una Color fijo original separado en RGB o HSL.
DX_PPU_FixedColor_Result 2 bytes Color fijo calculado después del efecto.
DX_PPU_FixedColor_LastGlobalEffectID 2 bytes Último efecto global calculado para el color fijo.
DX_PPU_PaletteColor00_Base 2 bytes Color 0,0 original.
DX_PPU_PaletteColor00_RGBBase / DX_PPU_PaletteColor00_HSLBase 3 bytes cada una Color 0,0 original separado en RGB o HSL.
DX_PPU_PaletteColor00_Result 2 bytes Color 0,0 que se quiere mostrar.
DX_PPU_PaletteColor00_LastGlobalEffectID 2 bytes Último efecto global calculado para el color 0,0.
DX_PPU_PaletteColor00_Update 1 byte Un valor distinto de 0 solicita copiar Result al color 0,0 durante NMI. Después de copiarlo, el sistema vuelve a poner esta variable en 0.

Transferencias pendientes

Estas variables guardan las copias que se realizarán durante NMI. Las macros de la sección PPU las rellenan por ti. Cada copia necesita un origen, un destino y una cantidad de bytes.

Variable Contenido
DX_PPU_VRAM_Transfer_Length Cantidad de copias de gráficos pendientes, en 1 byte.
DX_PPU_VRAM_Transfer_SourceLength Cantidad de bytes de cada copia, en valores de 2 bytes.
DX_PPU_VRAM_Transfer_Offset Destino de cada copia en VRAM, en valores de 2 bytes.
DX_PPU_VRAM_Transfer_Source Dirección de origen de cada copia, en valores de 2 bytes.
DX_PPU_VRAM_Transfer_SourceBNK Banco de origen de cada copia. La tabla reserva 2 bytes por entrada.
DX_PPU_CGRAM_Transfer_Length Cantidad de copias de colores pendientes, en 1 byte.
DX_PPU_CGRAM_Transfer_SourceLength Cantidad de bytes de cada copia, en valores de 2 bytes.
DX_PPU_CGRAM_Transfer_Offset Primer color de destino de cada copia, en valores de 1 byte.
DX_PPU_CGRAM_Transfer_Source Dirección de origen de cada copia, en valores de 2 bytes.
DX_PPU_CGRAM_Transfer_SourceBNK Banco de origen de cada copia.

Jugador y Yoshi

Estas variables permiten cambiar de dónde se obtienen los gráficos y colores del jugador y los gráficos de Yoshi. Los archivos gráficos deben conservar la organización que esperan las rutinas del juego.

Variable Tamaño Para qué sirve
DX_Dynamic_Player_GFX_Enable 1 byte 0 desactiva la carga de gráficos mediante este sistema; un valor distinto de 0 la activa.
DX_Dynamic_Player_GFX_Addr 2 bytes Dirección de inicio de los gráficos del jugador dentro del banco indicado.
DX_Dynamic_Player_GFX_BNK 2 bytes reservados Banco de origen de los gráficos del jugador. El banco se indica en el byte bajo.
DX_Dynamic_Player_Palette_Enable 1 byte 0 desactiva el manejo de paleta del jugador mediante este sistema; un valor distinto de 0 lo activa.
DX_Dynamic_Player_Palette_Addr 2 bytes Dirección de origen de la paleta del jugador.
DX_Dynamic_Player_Palette_BNK 1 byte Banco de la paleta. Cuando es 0, la rutina toma la dirección de paleta que utiliza el juego.
DX_Dynamic_Player_CustomPlayer / DX_Dynamic_Player_LastCustomPlayer 1 byte cada una Variables reservadas para identificar al jugador personalizado y el anterior. La inicialización las pone en 0 y $FF; actualmente no seleccionan por sí solas los gráficos de un personaje.
DX_Dynamic_Yoshi_VRAMEnable 1 byte 0 desactiva la carga de gráficos de Yoshi mediante este sistema; un valor distinto de 0 la activa.
DX_Dynamic_Yoshi_Addr 2 bytes Dirección de inicio de los gráficos de Yoshi dentro de su banco.
DX_Dynamic_Yoshi_BNK 1 byte Banco de origen de los gráficos de Yoshi.

Dibujo y variables de sprites

DX_Drawing_InitialIndexHighPriority y DX_Drawing_InitialIndexLowPriority ocupan 1 byte cada una y llevan la cuenta de las posiciones disponibles para dibujar sprites de prioridad alta o baja. DX_Drawing_OAMMap ocupa 128 bytes y ayuda a organizar los tiles dibujados. Estas variables se utilizan en la versión LoROM; el dibujo en SA-1 utiliza su manejo correspondiente.

Las variables individuales de sprites se definen en DynamicXSpritesTables.asm. Los archivos NormalSpriteDefines.asm, ClusterSpriteDefines.asm y ExtendedSpriteDefines.asm permiten utilizar los mismos nombres para los tres tipos:

Nombre para el sprite Qué guarda
!PoseIndex,x Pose que se quiere mostrar.
!LastPoseIndex,x Última pose que se consiguió y puede dibujarse. Se inicia en $FF.
!LastPoseHashIndex,x Entrada donde el sistema tiene registrada la ubicación de sus gráficos. Se inicia en $FF.
!GlobalFlip,x / !LocalFlip,x / !LastFlip,x Volteo general, volteo adicional de la pose y volteo que se utiliza para dibujar.
!Palette,x Paleta asignada: $00 para la 8, $02 para la 9, y así hasta $0E para la F. Se inicia en $FF cuando se utiliza asignación dinámica.
!PaletteOption,x Opciones EPPP----: efecto global y elección de paleta o grupo de paletas.
!PaletteAssignmentOption,x Modo de asignación: automático, manual o manual sin cargar colores.
!Version,x / !LastVersion,x Variante del sprite y última variante procesada al manejar su paleta. !LastVersion se inicia en $FF.
!RenderXDistanceOutOfScreen,x / !RenderYDistanceOutOfScreen,x Distancias que permiten seguir dibujando el sprite cuando su posición está fuera de la pantalla, pero alguna parte de su pose todavía puede verse.
!SafeFrameLowByte,x / !SafeFrameHighByte,x Último frame en que se intentó solicitar una pose, para evitar repetir el trabajo durante el mismo frame.
!AnimationIndex,x / !AnimationPoseIndex,x / !AnimationTimer,x Variables disponibles para llevar la cuenta de la animación, su paso actual y su temporizador. El código del recurso decide cómo utilizarlas.
!State,x Variable para el estado o comportamiento del recurso.

Cada variable de esta tabla ocupa 1 byte por sprite. Hay !MaxSprites entradas para normales, 20 para cluster y 10 para extended. No utilices !MaxSprites como cantidad de entradas de cluster o extended.

DX_FreeRams y DX_FreeRams2 marcan el comienzo de las áreas donde se colocan estas tablas. No representan memoria libre para guardar datos propios encima de las variables de sprites.

Defines fijos

Estos nombres representan configuraciones y direcciones conocidas. No son variables que cambian durante el juego.

Compatibilidad con LoROM y SA-1

DXDefines.asm detecta el tipo de ROM y elige los valores correspondientes. Utiliza estos nombres para que tu código funcione en ambos casos.

Define LoROM SA-1 Uso
!sa1 0 1 Permite elegir código distinto según el tipo de ROM.
!dp $0000 $3000 Ajuste de las direcciones de página directa.
!addr $0000 $6000 !addr.
!rom $800000 $000000 Ajuste utilizado al acceder a direcciones del código original del juego.
!MaxSprites $0C (12) $16 (22) Cantidad de posiciones de sprites normales.
!MultiplicationResult $4216 $2306 Dirección donde se lee el resultado de una multiplicación.
!DivisionResult $4214 $2306 Dirección donde se lee el cociente de una división.
!RemainderResult $4216 $2308 Dirección donde se lee el resto de una división.

Otros defines utilizados para colocar las variables son !normalBnk, !PalCopyBNK, !Variables y !Variables2. Normalmente basta con utilizar el nombre de cada variable DX_..., sin calcular su dirección a partir de estos valores.

Direcciones de gráficos en VRAM

Estos defines permiten indicar el destino de una transferencia sin escribir su dirección numérica. Cada familia tiene líneas de 0 a 7; sustituye N por el número de línea.

Familia Línea 0 Avance por línea Ejemplo
!FG1LineN $0000 $0100 !FG1Line1 = $0100
!FG2LineN $0800 $0100 !FG2Line1 = $0900
!BG1LineN $1000 $0100 !BG1Line1 = $1100
!FG3LineN $1800 $0100 !FG3Line1 = $1900
!BG2LineN $2000 $0100 !BG2Line1 = $2100
!BG3LineN $2800 $0100 !BG3Line1 = $2900
!LG1LineN a !LG4LineN $4000, $4400, $4800, $4C00 $0080 !LG1Line1 = $4080
!SP1LineN a !SP4LineN $6000, $6800, $7000, $7800 $0100 !SP4Line1 = $7900

!Layer1Tilemap = $3000 y !Layer2Tilemap = $3800 indican las direcciones habituales de los mapas de tiles de Layer 1 y Layer 2. Las direcciones de VRAM de esta sección se expresan en palabras de 2 bytes, como las que reciben las macros de transferencia.

Configuraciones de espacio para poses dinámicas

Los defines !DynamicSpaceConfig... se entregan a !DynamicPoseSpaceConfig. El nombre indica qué áreas de gráficos se permiten utilizar. FirstHalf significa primera mitad y SecondHalf, segunda mitad. Los nombres con WithPlayer o WithDSX corresponden a las configuraciones previstas para esos casos.

Valor Define
$00 !DynamicSpaceConfigSecondHalfSSP4
$01 !DynamicSpaceConfigSP4
$02 !DynamicSpaceConfigSecondHalfSP3
$03 !DynamicSpaceConfigFirstHalfSP3
$04 !DynamicSpaceConfigSP3
$05 !DynamicSpaceConfigSecondHalfSP2
$06 !DynamicSpaceConfigFirstHalfSP2
$07 !DynamicSpaceConfigSP2
$08 !DynamicSpaceConfigSecondHalfSP1
$09 !DynamicSpaceConfigFirstHalfSP1
$0A !DynamicSpaceConfigSP1
$0B !DynamicSpaceConfigFirstHalfSP1WithPlayer
$0C !DynamicSpaceConfigSP11WithPlayer
$0D !DynamicSpaceConfigSecondHalfSP3ndSP4
$0E !DynamicSpaceConfigSP34
$0F !DynamicSpaceConfigSecondHalfSP2andSP34
$10 !DynamicSpaceConfigSP234
$11 !DynamicSpaceConfigSecondHalfSP1andSP234
$12 !DynamicSpaceConfigSP1234
$13 !DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer
$14 !DynamicSpaceConfigSP1234WithPlayer
$15 !DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX
$16 !DynamicSpaceConfigSP34WithDSX
$17 !DynamicSpaceConfigSecondHalfSP2andSP34WithDSX
$18 !DynamicSpaceConfigSP234WithDSX
$19 !DynamicSpaceConfigSecondHalfSP1andSP234WithDSX
$1A !DynamicSpaceConfigSP1234WithDSX
$1B !DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX
$1C !DynamicSpaceConfigSP1234WithPlayerAndDSX

Los nombres de esta tabla se escriben exactamente como aparecen en DXDefines.asm, incluidos nombres como SecondHalfSSP4 y SP11WithPlayer.

Otras constantes

Define Valor o uso
!AN2Buffer1 / !AN2Buffer2 Direcciones $7EC100 y $7EAD00 utilizadas para datos de animación.
!GFX32Buffer $7E2000, dirección del buffer habitual de GFX32.
!PlayerPaletteColor2To5 $00B280, datos de los colores 2-5 de la paleta del jugador.
!PlayerBasePalette $00B2C8, datos de la paleta base del jugador.
!VRAMTransferSize / !CGRAMTransferSize Ambos valen 64 en la plantilla actual. Se utilizan para reservar las tablas de transferencias; no representan el límite de bytes que se cargan por frame.

Las opciones de instalación, como !DynamicPoses, !DrawingSystem, !GraphicsChange, !PalettesChange, !PalettesEffects, !PlayerFeatures y !YoshiFeatures, se incluyen desde Options.asm. Sus valores indican qué funciones se instalaron; no se cambian durante el juego.

Defines generados

Dynamic Xtreme crea estos defines al instalar los recursos y los añade a DXDefines.asm. Utiliza sus nombres en lugar de copiar los valores numéricos, porque los IDs, direcciones y tamaños pueden cambiar cuando se agregan o modifican recursos.

Los nombres se normalizan en PascalCase: se eliminan espacios, guiones bajos, guiones y otros separadores, y se pone en mayúscula la inicial de cada palabra. Por ejemplo, my_sprite, my-sprite y my sprite se convierten en MySprite. Se conserva el resto de las mayúsculas y minúsculas que ya tenía el nombre. Ante una duda, copia el nombre exacto de DXDefines.asm.

Poses dinámicas y poses de dibujo

Familia o ejemplo Qué representa
!DynamicPoseIDMySprite000 ID de unos gráficos de pose declarados en el DynamicInfo. Se utiliza para solicitar su carga con !Upload.
!DynamicPoseMySprite000 Dirección ROM de esos gráficos.
!DynamicPoseMySprite000Size Tamaño de esos gráficos en bytes.
!PoseIDMySprite_Frame0 ID de una pose del DrawInfo. Se utiliza para dibujarla con !DXDraw o DrawStatic.
!RenderBoxXDistanceOutOfScreenMySprite Distancia horizontal calculada desde el DrawInfo para saber cuándo el sprite deja de verse.
!RenderBoxYDistanceOutOfScreenMySprite Distancia vertical calculada desde el DrawInfo para la misma comprobación.

El ID dinámico elige qué gráficos cargar; el ID de dibujo elige cómo colocar los tiles para formar la pose. Son valores distintos. Un define !DynamicPoseID... no se utiliza en lugar de un !PoseID....

Paletas y efectos

Familia o ejemplo Qué representa
!PaletteIDMyPalette ID de una paleta declarada desde el DynamicInfo.
!PaletteMyPalette Dirección ROM de sus colores.
!PaletteMyPaletteSize Tamaño de la paleta en bytes.
!MySpritePaletteTableOffset Indica dónde comienza la lista de paletas de ese DynamicInfo. Se entrega a !PaletteAssignment y a sus variantes.
!PaletteEffectIDMyEffect0 ID de un efecto de my_effect.paleffect. El número final identifica el efecto dentro del archivo; los IDs globales comienzan en 1.
!PaletteMyTargetRGB / !PaletteMyTargetHSL Dirección ROM de una paleta de destino convertida para una transición RGB o HSL. Se genera cuando un efecto necesita esa paleta.
!PaletteMyTargetRGBSize / !PaletteMyTargetHSLSize Tamaño en bytes de esas paletas convertidas.

Los nombres de los ejemplos usan la misma normalización: my_palette pasa a MyPalette y my_effect a MyEffect. Los defines se generan durante la instalación y quedan en DXDefines.asm.

Recursos generales y buffers

Familia o ejemplo Qué representa
!ResourceIDMyResource ID de un recurso general del DynamicInfo.
!ResourceMyResource Dirección ROM de ese recurso.
!ResourceMyResourceSize Tamaño del recurso en bytes.
!BufferIDMyBuffer ID de un buffer insertado por la herramienta.
!BufferMyBuffer Dirección del buffer insertado en la ROM; no es una variable temporal de RAM.
!BufferMyBufferSize Tamaño del buffer en bytes.

Los nombres dependen de los recursos instalados. Se normalizan del mismo modo: my_resource pasa a MyResource. Consulta DXDefines.asm para ver los nombres y valores de tu instalación.

Cantidades y tablas generadas

Estos defines permiten consultar las cantidades y las tablas creadas al instalar los recursos. Para un sprite normal suele bastar con utilizar los IDs individuales de las tablas anteriores.

Define Qué representa
!NumberOfDynamicPoses / !NumberOfPoses Cantidad de poses dinámicas y de poses de dibujo instaladas, respectivamente.
!NumberOfPalettes / !NumberOfResources / !NumberOfBuffers Cantidad de paletas normales, recursos generales y buffers insertados.
!NumberOfPaletteEffects Valor usado para dimensionar las tablas de efectos. La generación incluye el espacio del ID 0; no lo interpretes como cantidad de efectos escritos en un archivo *.paleffect.
!PaletteTableSize Cantidad total de entradas en las listas de paletas de los DynamicInfo.
!PaletteIDTables Dirección de la tabla de IDs de esas listas de paletas.
!PaletteAddrTables Dirección de la tabla con las direcciones ROM de sus colores.
!PaletteEffectsTypes Tabla con el tipo de cada efecto instalado.
!PaletteEffectsChannels1, !PaletteEffectsChannels2, !PaletteEffectsChannels3 Tablas con los valores de color de cada efecto.
!PaletteEffectsRatios1, !PaletteEffectsRatios2, !PaletteEffectsRatios3 Tablas con los ratios que controlan cuánto se aplica cada cambio.
!BufferTable, !PaletteTables, !PaletteEffectsTable Direcciones de las tablas que el parche publica para esos datos.

Defines de rutinas

Estos defines representan llamadas del sistema, no variables para guardar datos. La tabla sirve para encontrarlas; su uso se explica en las secciones de rutinas y macros.

Define o familia Uso
!AllowedGameMode Comprueba si el modo de juego actual permite procesar las operaciones correspondientes.
!DynamicPoseSpaceConfig Elige las partes de VRAM disponibles para poses dinámicas.
!TakeDynamicRequest Solicita una pose por su ID.
!DynamicRoutine Prepara las copias de gráficos de una pose a VRAM.
!SetPropertyAndOffset Obtiene la ubicación y propiedades de los gráficos de una pose dinámica para dibujarla.
!Draw / !Draw_Return Entrada y punto de retorno utilizados por las rutinas de dibujo.
!RemapOamTile Ajusta el número de tile para utilizar la ubicación real de los gráficos dinámicos.
!IsValid, !XIsValid, !YIsValid Comprobaciones utilizadas por el dibujo para decidir si un tile puede mostrarse.
!AssignPalette Selecciona el destino de una paleta según el modo de asignación.
!LoadPaletteOnBuffer Carga datos de paleta en un espacio de trabajo para procesarlos.
!SetRGBBase / !SetHSLBase Prepara los colores para calcular efectos RGB o HSL.
!RGBToHSL / !HSLToRGB Convierte entre ambos sistemas de color.
!RGBMerge Convierte colores RGB separados al formato de paleta de SNES.
!Mix... / !MixAndMerge... Aplica cambios a uno o varios componentes del color.
!PalTransitionRGB / !PalTransitionHSL Calcula el cambio de una paleta a otra.
!PalTransitionAndMergeRGB / !PalTransitionAndMergeHSL Calcula la transición y deja el resultado en formato de SNES.
!DoEffect / !DoEffectAndMerge Aplica un efecto mediante su ID.
!PalFunctionRGB, !PalFunctionHSL y variantes AndMerge Nombres reservados para funciones de color que todavía no están implementadas.

!Routines es la dirección de la tabla desde la que se obtienen estas llamadas. No necesitas calcular sus posiciones para usar los defines publicados.

Estado del CPU y memoria temporal

Cada llamada necesita que los registros tengan el tamaño indicado en su entrada. Un registro puede terminar en 8 bits y aun así haber perdido su valor anterior: tamaño y contenido son cosas distintas.

Estas reglas se aplican a las llamadas de este artículo, salvo las excepciones indicadas en cada entrada:

  • Ejecuta el código en modo nativo, con el modo decimal desactivado. Las operaciones matemáticas del sistema utilizan números binarios.
  • Direct page D: $0000 en LoROM y $3000 en el contexto habitual de SA-1 Pack. Las direcciones cortas como $00 se interpretan respecto de esa base. Las llamadas no preparan ni cambian D por ti.
  • Banco de datos DBR: debe permitir acceder a los espejos de RAM y a los registros hardware utilizados por la llamada. El contexto habitual usa bancos con esos espejos, como $00-$3F o $80-$BF. Si entregas un operando que lee una tabla mediante una dirección de 16 bits, DBR también debe permitir leer esa tabla. Un puntero de 24 bits lleva su propio banco. DynamicRoutine tiene un requisito específico de DBR, explicado en su entrada.
  • Las llamadas conservan DBR y D. Algunas cambian DBR temporalmente y lo restauran antes de retornar. Esto no significa que cualquier banco de entrada sea válido.
  • Flags: utiliza como resultado únicamente los que se indiquen expresamente. No supongas que N, Z, V o carry conservan su valor anterior. Los cambios de tamaño de A y X/Y se indican por llamada.
  • Memoria temporal: las scratch indicadas pueden sobrescribirse tanto en éxito como en fallo. Guarda fuera de ellas cualquier dato que necesites después. Las salidas solo son válidas en las condiciones descritas en cada entrada.
  • Pila: las llamadas retiran los datos temporales que ellas mismas apilan. Tu código debe emparejar sus propios pushes y pulls con el mismo tamaño de registro, y respetar el retorno de la rutina o macro.

Para conservar un registro, guárdalo antes de la llamada y recupéralo después con el mismo tamaño. Si necesitas comprobar el carry devuelto, hazlo antes de ejecutar otra operación que lo modifique; restaurar P mediante PLP también reemplaza ese carry.

Rutinas para sprites

Estas rutinas permiten comprobar si un sprite debe dibujarse en pantalla, cargar sus gráficos y manejar sus paletas. Antes de utilizarlas, incluye el archivo de defines correspondiente: NormalSpriteDefines.asm, ClusterSpriteDefines.asm o ExtendedSpriteDefines.asm. La ruta del include es relativa al archivo ASM del sprite.

Los requisitos de DBR, D, flags y pila se explican en Estado del CPU y memoria temporal. La tabla siguiente distingue el tamaño de los registros de los valores que conservan.

Para usar llamadas como !RenderBox o !Upload, escribe su nombre directamente, como muestran los ejemplos. No añadas JSR ni JSL delante. Salvo que se indique lo contrario, X debe contener el número del slot que ocupa el sprite.

Registros y scratch de las llamadas para sprites

Entra con X e Y en modo de 8 bits. El tamaño de A depende de la llamada:

Llamada A al entrar Registros al volver Scratch que puede sobrescribir
!RenderBox 8 bits. A cambia y queda en 8 bits. X e Y conservan su valor y tamaño. No utiliza scratch; modifica las tablas de Dynamic Xtreme descritas en su entrada.
!PaletteAssignment y !PaletteAssignmentNoUpload 16 bits con PalettesChange habilitado; 8 bits si está deshabilitado, sin utilizar el offset de tabla. A e Y pueden cambiar. X vuelve a cargarse desde !SpriteIndex cuando se utiliza para el trabajo interno. La variante sin carga devuelve información en Y. Los tres quedan en 8 bits. $00-$0F, $65-$67, $D5, según el camino utilizado. Con efectos, también puede utilizar los temporales de efectos indicados más abajo.
!Upload y !UploadWithoutPoseOffset 16 bits. A e Y pueden cambiar. X se recupera desde !SpriteIndex. Los tres quedan en 8 bits. $00-$0F y $47-$51 cuando necesita preparar una carga nueva.
!DXDraw y !DXDrawWithOffset 16 bits. A e Y pueden cambiar. Si dibuja, X se recupera desde !SpriteIndex; si no hay pose válida, conserva el X de entrada. Los tres quedan en 8 bits. $00-$0F, $45-$4F y $8A. Con desplazamiento adicional, también $8B-$8C.
!ReplacePalette 8 bits. A e Y pueden cambiar. X se recupera desde !SpriteIndex. Los tres quedan en 8 bits. $00-$01 y los temporales utilizados por la carga de colores; también los de efectos cuando corresponde.
!ConcatenateRGBPaletteEffectToGlobal y variante HSL 16 bits. A e Y pueden cambiar. Aunque X recibe una paleta al entrar, al volver contiene !SpriteIndex. Los tres quedan en 8 bits. Los temporales de efectos, $05-$06 y $F0-$F3.

PIXI mantiene !SpriteIndex como el índice del sprite actual. Si cambias X temporalmente, las llamadas que recuperan ese índice no conservan necesariamente el X que tú les entregaste. En particular, después de concatenar un efecto, X vuelve a identificar al sprite, no a su paleta. Los aliases de PIXI realizan la llamada y después continúan en la instrucción siguiente; el RTS de los ejemplos pertenece a la rutina del sprite.

RenderBox

!RenderBox comprueba si el sprite está en pantalla o lo bastante cerca de sus bordes como para seguir dibujándose. Se utiliza al comienzo de la rutina principal para decidir si ejecutar solo su lógica (short routine) o también cargar sus gráficos, manejar su paleta y dibujarlo (long routine).

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalRenderBox().
  • Cluster sprite: %DXClusterRenderBox().
  • Extended sprite: %DXExtendedRenderBox().

Entradas

  • X: índice del sprite.
  • !RenderXDistanceOutOfScreen,x y !RenderYDistanceOutOfScreen,x: distancias horizontal y vertical permitidas fuera de la pantalla.

Resultado

  • Carry activado: el sprite está en pantalla o dentro de la distancia permitida fuera de sus bordes; se debe ejecutar la long routine.
  • Carry desactivado: el sprite está demasiado lejos de la pantalla para dibujarse; se debe ejecutar la short routine.

Cuando el sprite está demasiado lejos, establece !Palette, !LastVersion, !LastPoseIndex y !LastPoseHashIndex en $FF. Esto indica que deberá volver a obtener su paleta y su pose cuando se acerque a la pantalla. También guarda en !LastFlip el volteo que resulta de combinar !GlobalFlip y !LocalFlip. En sprites normales actualiza además las variables que indican si está fuera de pantalla horizontal o verticalmente.

Ejemplo

print "INIT ",pc
    LDA.b #!RenderBoxXDistanceOutOfScreenMySprite
    STA !RenderXDistanceOutOfScreen,x
    LDA.b #!RenderBoxYDistanceOutOfScreenMySprite
    STA !RenderYDistanceOutOfScreen,x
    ; Aquí va el resto de la inicialización del sprite
RTL

SpriteCode:
    !RenderBox
    BCS .LongRoutine

.ShortRoutine
    LDA #$00
    %SubOffScreen()
    ; Aquí va la lógica de tu sprite
RTS

.LongRoutine
    ; Aquí van el manejo de paletas, poses y dibujo
    ; y la lógica de tu sprite
RTS

La llamada a %SubOffScreen() del ejemplo corresponde a sprites normales y recibe en A un valor entre 0 y 7 para seleccionar la configuración de eliminación fuera de pantalla. El ejemplo utiliza 0, el valor habitual. Se recomienda utilizarla en la short routine; dentro de la long routine resulta redundante.

Los defines !RenderBoxXDistanceOutOfScreenMySprite y !RenderBoxYDistanceOutOfScreenMySprite se generan desde el DrawInfo y se guardan en DXDefines.asm. El nombre del recurso se normaliza en PascalCase: se eliminan separadores como espacios, guiones bajos y guiones, y se escribe en mayúscula la inicial de cada palabra. Por ejemplo, my_sprite se convierte en MySprite. Si el sprite utiliza varios DrawInfo, utiliza la mayor distancia horizontal y la mayor distancia vertical entre ellos.

PaletteAssignment

!PaletteAssignment selecciona una paleta del DynamicInfo usando !Version,x, le asigna una de las paletas de sprites 8-F y carga sus colores cuando hace falta. Si el sprite ya tiene esa paleta, mantiene su temporizador de uso en 2 para evitar que otro recurso la reemplace. Debe llamarse en cada frame de la long routine; esto no significa que los colores vuelvan a cargarse cada vez.

Si el bit E de !PaletteOption,x está activado ($80), también procesa los efectos globales de paleta correspondientes. Si está desactivado, la paleta queda excluida del efecto global.

Cómo se elige la paleta

!Version,x selecciona una paleta de la lista del DynamicInfo: 0 elige la primera, 1 la segunda, etc. Por ejemplo, si la lista contiene una paleta roja y otra azul, las versiones 0 y 1 seleccionan esos colores. El sprite también puede usar esta variable para cambiar su comportamiento; la rutina de paletas solo la utiliza para elegir los colores.

!PaletteOption,x indica qué paleta de sprites se permite utilizar y si sus colores reciben el efecto global. Su formato es EPPP----:

  • E: 0 excluye la paleta del efecto global; 1 permite aplicarlo.
  • PPP: con asignación manual, selecciona una paleta entre 8 y F. 000 elige la 8, 001 la 9, y así hasta 111 para la F.
  • Con asignación automática, PPP = 000 permite buscar entre las ocho paletas. Un valor 0XX distinto de 000 limita la búsqueda a las paletas 8-B; un valor 1XX la limita a las C-F.
  • Los cuatro bits bajos no se utilizan para estas opciones.

!PaletteAssignmentOption,x decide quién elige el destino y si se cargan colores. Su formato es --AA----:

  • AA = 00 ($00): automático. Dynamic Xtreme elige una de las paletas permitidas y carga los colores del DynamicInfo.
  • AA = 01 ($10): manual. Utiliza la paleta indicada en PPP y carga los colores del DynamicInfo.
  • AA = 10 ($20): manual sin carga. Utiliza la paleta indicada en PPP con los colores que ya tiene el nivel.

En sprites normales, !PaletteOption,x es !ExtraByte1,x y !PaletteAssignmentOption,x es !ExtraProp2,x. Lo habitual es usar el primer Extra Byte con formato EPPPVVVV y copiar sus cuatro bits bajos a !Version,x durante el INIT. Así se puede elegir la versión desde Lunar Magic. En cluster y extended, el código que crea el sprite debe establecer estas variables.

Por ejemplo, con asignación manual, !PaletteOption,x = $A0 utiliza la paleta A y permite el efecto global. Si !Version,x = 1, carga en ella la segunda paleta de la lista del DynamicInfo.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalPaletteAssignment().
  • Cluster sprite: %DXClusterPaletteAssignment().
  • Extended sprite: %DXExtendedPaletteAssignment().

Entradas

  • A de 16 bits: el define !MySpritePaletteTableOffset correspondiente al DynamicInfo que contiene las paletas.
  • X: índice del sprite.
  • !Version,x: índice de la paleta dentro de la tabla.
  • !LastVersion,x: última versión procesada. Se compara con !Version,x para detectar cambios y debe inicializarse en $FF.
  • !PaletteOption,x: selección de paleta y participación en el efecto global.
  • !PaletteAssignmentOption,x: asignación automática, manual o manual sin carga.

Resultado

  • Carry activado: el sprite puede dibujarse con la paleta asignada.
  • Carry desactivado: el sprite todavía no tiene una paleta lista para dibujar.
  • !Palette,x: paleta asignada, con valores de $00 a $0E de dos en dos para las paletas 8-F.
  • !LastVersion,x: se actualiza con !Version,x cuando se procesa la nueva asignación.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

PaletteManagement:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    !PaletteAssignment
RTS

!MySpritePaletteTableOffset se genera desde el DynamicInfo y se guarda en DXDefines.asm. El nombre del recurso se normaliza en PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: my_sprite se convierte en MySprite.

PaletteAssignmentNoUpload

!PaletteAssignmentNoUpload elige la paleta igual que !PaletteAssignment, pero deja pendiente la carga de los colores. Se utiliza cuando primero necesitas modificar la paleta, por ejemplo aplicando un efecto local y combinándolo con el global. Si ya estaba asignada, mantiene su temporizador de uso en 2 para evitar que otro recurso la reemplace.

El bit E de !PaletteOption,x ($80) también determina si la paleta participa en los efectos globales. Esta variante prepara la asignación y la paleta base; la aplicación final de los efectos y la carga se completan mediante la rutina posterior, como !ConcatenateRGBPaletteEffectToGlobal o !ConcatenateHSLPaletteEffectToGlobal.

!Version,x elige la paleta del DynamicInfo: 0 para la primera, 1 para la segunda, etc. !PaletteOption,x utiliza EPPP----: E permite el efecto global y PPP selecciona la paleta 8-F en modo manual, o el grupo donde buscarla en modo automático. En automático, 000 permite todas, 0XX distinto de cero permite 8-B y 1XX permite C-F.

!PaletteAssignmentOption,x utiliza --AA----: $00 elige el destino automáticamente, $10 usa el indicado en PPP y $20 utiliza los colores que ya tiene el nivel. Para preparar una paleta que después recibirá un efecto local, utiliza uno de los modos que toman los colores del DynamicInfo: automático o manual con carga.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalPaletteAssignmentNoUpload().
  • Cluster sprite: %DXClusterPaletteAssignmentNoUpload().
  • Extended sprite: %DXExtendedPaletteAssignmentNoUpload().

Entradas

  • A de 16 bits: el define !MySpritePaletteTableOffset del DynamicInfo que contiene las paletas.
  • X: índice del sprite.
  • !Version,x, !PaletteOption,x y !PaletteAssignmentOption,x: mismas opciones que en !PaletteAssignment.
  • !LastVersion,x: última versión procesada, utilizada para detectar cambios respecto de !Version,x. Debe inicializarse en $FF.

Resultado

  • Carry activado: el sprite tiene una paleta asignada; desactivado si no pudo obtenerse.
  • !Palette,x: paleta asignada.
  • !LastVersion,x: se actualiza con !Version,x cuando se procesa la nueva asignación.
  • $00-$01: número que identifica la paleta elegida del DynamicInfo, cuando se utiliza un modo que carga sus colores.
  • $02-$04: dirección de la paleta base en ROM.
  • Y = 1: se acaba de asignar la paleta y hay que calcular su efecto; Y = 0: no es necesario recalcularlo por una asignación nueva. Entrega este valor a la rutina de concatenación.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

    REP #$20
    LDA #!MySpritePaletteTableOffset
    !PaletteAssignmentNoUpload
    BCC .Return

    ; Aquí se prepara y concatena el efecto.
    ; Conserva Y y la dirección de $02-$04 para esa llamada.
.Return
RTS

$00-$01 dice qué paleta del DynamicInfo se eligió; !Palette,x dice cuál de las paletas 8-F utilizará el sprite para dibujarse. Los datos de $00-$04 solo se preparan cuando la rutina lee la paleta del DynamicInfo. Si usas el modo manual sin carga, deshabilitaste los cambios de paleta o la llamada no se procesa en el modo de juego actual, no utilices esos datos como resultado de la llamada.

!MySpritePaletteTableOffset se genera desde el DynamicInfo y queda en DXDefines.asm. Su nombre se normaliza en PascalCase: my_sprite pasa a MySprite, eliminando los separadores.

Upload

!Upload consigue los gráficos de la pose que el sprite quiere mostrar. La pose se selecciona sumando !PoseIndex,x al ID dinámico recibido en A. Si sus gráficos ya están en VRAM, solo actualiza su registro de último uso para evitar que sean sobrescritos. Si todavía no están, solicita su carga. Debe llamarse en cada frame de la long routine.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalUpload().
  • Cluster sprite: %DXClusterUpload().
  • Extended sprite: %DXExtendedUpload().

Entradas

  • A de 16 bits: ID dinámico base.
  • X: índice del sprite.
  • !PoseIndex,x: índice que se suma al ID base.
  • !GlobalFlip,x y !LocalFlip,x: volteos que se combinarán para dibujar.

Resultado

  • Carry activado: el sprite tiene una pose disponible para dibujar. Puede ser la solicitada o la anterior si todavía no fue posible cargar la nueva.
  • Carry desactivado: el sprite todavía no tiene una pose disponible.
  • !LastPoseIndex,x, !LastPoseHashIndex,x y !LastFlip,x: estado de la pose disponible para dibujar.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

PoseManagement:
    REP #$20
    LDA #!DynamicPoseIDMySprite000
    !Upload
RTS

!DynamicPoseIDMySprite000 se genera desde el DynamicInfo y queda en DXDefines.asm. El nombre se normaliza en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra, como my_sprite → MySprite.

UploadWithoutPoseOffset

!UploadWithoutPoseOffset solicita directamente el ID dinámico entregado en A, sin sumarle !PoseIndex. Como !Upload, reutiliza los gráficos si ya están en VRAM y puede seguir mostrando la pose anterior mientras no consiga cargar la nueva.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalUploadWithoutPoseOffset().
  • Cluster sprite: %DXClusterUploadWithoutPoseOffset().
  • Extended sprite: existe %DXExtendedUploadWithoutPoseOffset(), pero actualmente ExtendedSpriteDefines.asm no publica el alias !UploadWithoutPoseOffset.

Entradas

  • A de 16 bits: ID dinámico exacto.
  • X: índice del sprite.
  • !GlobalFlip,x y !LocalFlip,x: volteos del sprite.

Resultado

  • Carry activado: el sprite tiene una pose disponible para dibujar; desactivado si todavía no tiene ninguna.
  • Guarda la pose que se puede dibujar en !LastPoseIndex,x y la ubicación de sus gráficos en !LastPoseHashIndex,x, igual que !Upload.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

PoseManagement:
    REP #$20
    LDA #!DynamicPoseIDMySprite003
    !UploadWithoutPoseOffset
RTS

!DynamicPoseIDMySprite003 se genera desde el DynamicInfo y queda en DXDefines.asm. El nombre usa PascalCase eliminando separadores: my_sprite se convierte en MySprite.

DXDraw

!DXDraw dibuja una pose utilizando los gráficos dinámicos disponibles para el sprite.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalDraw().
  • Cluster sprite: %DXClusterDraw().
  • Extended sprite: %DXExtendedDraw().

Entradas

  • A de 16 bits: ID de la pose de dibujo.
  • X: índice del sprite.
  • !PropParam ($52): propiedades adicionales, con formato YXCC----.
  • !MaxTilePriorityParam ($0A): prioridad máxima de los tiles; $00 máxima, $01 alta, $02 propia del tipo de sprite y $03 mínima.
  • !Palette,x, !LastFlip,x y !LastPoseHashIndex,x: paleta, volteo y ubicación de los gráficos disponibles.

Resultado

Dibuja la pose en pantalla. Si !LastPoseHashIndex,x contiene $FF, no dibuja. A, X e Y quedan en modo de 8 bits.

Ejemplo

Draw:
    LDA #$20
    STA !PropParam
    LDA #$02
    STA !MaxTilePriorityParam

    LDA !LastPoseIndex,x
    REP #$21
    AND #$00FF
    ADC #!PoseIDMySprite_Frame0
    !DXDraw
RTS

En este ejemplo, las poses deben estar en el mismo orden en el DrawInfo y el DynamicInfo. Se utiliza !LastPoseIndex porque indica qué pose se puede dibujar: si la nueva todavía no se pudo cargar, seguirá mostrando la anterior.

!PoseIDMySprite_Frame0 se genera desde el DrawInfo y queda en DXDefines.asm. Los nombres de recurso y pose se normalizan en PascalCase eliminando separadores, como my_sprite → MySprite. Este ID de dibujo es distinto de los IDs !DynamicPoseID... del DynamicInfo.

DXDrawWithOffset

!DXDrawWithOffset permite dibujar la pose unos píxeles a la derecha, izquierda, arriba o abajo de la posición del sprite. Solo mueve el dibujo; el sprite sigue moviéndose y chocando en su posición original.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalDrawWithOffset().
  • Cluster sprite: %DXClusterDrawWithOffset().
  • Extended sprite: %DXExtendedDrawWithOffset().

Entradas

  • Las mismas entradas de !DXDraw.
  • !XOffsetParam ($8A): desplazamiento horizontal de 8 bits con signo.
  • !YOffsetParam ($8B): desplazamiento vertical de 8 bits con signo.

Resultado

Dibuja igual que !DXDraw, pero suma los desplazamientos que preparaste. Un valor positivo en !XOffsetParam mueve el dibujo a la derecha; en !YOffsetParam, hacia abajo. Los valores negativos lo mueven a la izquierda o hacia arriba.

Ejemplo

Draw:
    LDA #$08
    STA !XOffsetParam
    LDA #$F8
    STA !YOffsetParam
    LDA #$20
    STA !PropParam
    LDA #$02
    STA !MaxTilePriorityParam

    LDA !LastPoseIndex,x
    REP #$21
    AND #$00FF
    ADC #!PoseIDMySprite_Frame0
    !DXDrawWithOffset
RTS

El ejemplo desplaza el dibujo 8 píxeles a la derecha y 8 hacia arriba. !PoseIDMySprite_Frame0 se genera desde el DrawInfo y queda en DXDefines.asm; el nombre se normaliza en PascalCase eliminando separadores, como my_sprite → MySprite.

ReplacePalette

!ReplacePalette cambia los colores de la paleta que el sprite ya tiene asignada, sin cambiar su ID de asignación. Por ejemplo, permite sustituir su paleta normal por otra durante un estado especial. Como varios sprites pueden compartir esa paleta, todos ellos verán el cambio. Llámala cuando necesites cambiar los colores; repetirla cada frame obliga al sistema a volver a preparar la paleta y sus efectos.

Suele utilizarse después de !PaletteAssignmentNoUpload: primero se asigna la paleta sin cargar sus colores y después se reemplazan por los que quieres mostrar. Antes de llamar a !ReplacePalette, coloca en $02-$04 la dirección de los nuevos colores.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalReplacePalette().
  • Cluster sprite: %DXClusterReplacePalette().
  • Extended sprite: %DXExtendedReplacePalette().

Entradas

  • X: índice del sprite.
  • A en modo de 8 bits.
  • $02-$04: dirección ROM de la nueva paleta en BGR555.
  • !Palette,x: paleta ya asignada.
  • !PaletteOption,x: participación en el efecto global.

Resultado

  • Carry activado: se puede dibujar con la paleta; si los nuevos colores todavía no están listos, se conservan los anteriores.
  • Carry desactivado: la paleta todavía no tiene colores listos para dibujar.

Mantiene el mismo ID de paleta, pero solicita cambiar sus colores. Al marcar que el efecto debe volver a calcularse, utiliza $FFFF si nunca se habían obtenido colores para dibujar, o $FFFE si puede seguir mostrando los anteriores mientras prepara los nuevos.

Ejemplo

ReplaceSpritePalette:
    ; Ejecutar cuando se necesite cambiar una paleta ya asignada.
    LDA.b #!PaletteMyAlternatePalette
    STA $02
    LDA.b #!PaletteMyAlternatePalette>>8
    STA $03
    LDA.b #!PaletteMyAlternatePalette>>16
    STA $04
    !ReplacePalette
RTS

!PaletteMyAlternatePalette es la dirección de una paleta insertada desde los recursos declarados en un DynamicInfo y se guarda en DXDefines.asm. Su nombre se normaliza en PascalCase: my_alternate_palette se convierte en MyAlternatePalette.

ConcatenateRGBPaletteEffectToGlobal

!ConcatenateRGBPaletteEffectToGlobal permite que la paleta del sprite tenga un efecto RGB propio y siga siendo afectada por el efecto global. Primero aplica el efecto local, como PaletteTransitionRGB, y después aplica el global sobre ese resultado. Llámala después de !PaletteAssignmentNoUpload, que deja preparada la paleta original.

El uso habitual es asignar primero la paleta con !PaletteAssignmentNoUpload y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalConcatenateRGBPaletteEffectToGlobal().
  • Cluster sprite: %DXClusterConcatenateRGBPaletteEffectToGlobal().
  • Extended sprite: %DXExtendedConcatenateRGBPaletteEffectToGlobal().

Entradas

  • A de 16 bits: ID del efecto local RGB.
  • X de 8 bits: copia aquí el valor de !Palette,x con LDA !Palette,x seguido de TAX, como en el ejemplo.
  • Y de 8 bits: conserva el valor que dejó !PaletteAssignmentNoUpload. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.
  • $02-$04: dirección de la paleta base BGR555 preparada por la asignación.
  • !PaletteOption: el bit E debe estar activado para combinar con el efecto global.

Resultado

  • Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.
  • Carry desactivado: todavía no hay colores listos para dibujar esa paleta.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

PaletteManagement:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    !PaletteAssignmentNoUpload
    BCC .Return

    LDA !Palette,x
    TAX
    REP #$20
    LDA #!PaletteEffectIDMyRGBEffect0
    !ConcatenateRGBPaletteEffectToGlobal
.Return
RTS

!MySpritePaletteTableOffset se genera desde el DynamicInfo y !PaletteEffectIDMyRGBEffect0 desde un archivo *.paleffect. Ambos quedan en DXDefines.asm. Sus nombres se normalizan en PascalCase eliminando separadores, como my_sprite → MySprite. Si se necesita Y para seleccionar el efecto mediante una tabla, conserva su valor con PHY y restáuralo con PLY antes de concatenar.

ConcatenateHSLPaletteEffectToGlobal

!ConcatenateHSLPaletteEffectToGlobal permite que la paleta del sprite tenga un efecto HSL propio, como MixH, y siga siendo afectada por el efecto global. Primero aplica el efecto local y después el global. Llámala después de !PaletteAssignmentNoUpload, que deja preparada la paleta original.

El uso habitual es asignar primero la paleta con !PaletteAssignmentNoUpload y, si el carry está activado, llamar a esta rutina para aplicar los efectos y completar la carga de los colores.

Rutina utilizada según el tipo de sprite

  • Sprite normal: %DXNormalConcatenateHSLPaletteEffectToGlobal().
  • Cluster sprite: %DXClusterConcatenateHSLPaletteEffectToGlobal().
  • Extended sprite: %DXExtendedConcatenateHSLPaletteEffectToGlobal().

Entradas

  • A de 16 bits: ID del efecto local HSL.
  • X de 8 bits: copia aquí el valor de !Palette,x con LDA !Palette,x seguido de TAX, como en el ejemplo.
  • Y de 8 bits: conserva el valor que dejó !PaletteAssignmentNoUpload. El valor 1 obliga a calcular de nuevo el efecto; 0 permite reutilizar el resultado anterior si no cambió nada.
  • $02-$04: dirección de la paleta base BGR555 preparada por la asignación.
  • !PaletteOption: el bit E debe estar activado para combinar con el efecto global.

Resultado

  • Carry activado: se puede dibujar con la paleta. Si el nuevo efecto todavía no está listo, se sigue mostrando el anterior.
  • Carry desactivado: todavía no hay colores listos para dibujar esa paleta.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

PaletteManagement:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    !PaletteAssignmentNoUpload
    BCC .Return

    LDA !Palette,x
    TAX
    REP #$20
    LDA #!PaletteEffectIDMyHSLEffect0
    !ConcatenateHSLPaletteEffectToGlobal
.Return
RTS

!MySpritePaletteTableOffset se genera desde el DynamicInfo y !PaletteEffectIDMyHSLEffect0 desde un archivo *.paleffect. Quedan en DXDefines.asm y utilizan nombres normalizados en PascalCase: se eliminan separadores y se escribe en mayúscula la inicial de cada palabra. Conserva Y con PHY/PLY si lo utilizas temporalmente para seleccionar el efecto.

Ambas variantes de concatenación realizan las conversiones necesarias si el efecto local y el global utilizan espacios de color diferentes. Consulta Tipos de efectos para identificar los efectos RGB y HSL.

Rutinas y Macros Generales

Estas rutinas y macros permiten trabajar con los sistemas de Dynamic Xtreme desde sprites, UberASM y otros códigos. En las macros puedes indicar qué variables y valores utilizar. Si un argumento contiene una coma, como !NormalPoseIndex,x, escríbelo entre comillas para que Asar lo lea como un solo argumento. Utiliza # al entregar un valor inmediato, como #$04.

Aplica también las reglas de DBR, direct page, flags y pila. Los contratos de cada familia indican qué registros y temporales debes guardar si necesitas conservarlos.

Consulta rápida de llamadas y retornos

Algunas macros ya incluyen el retorno que termina la rutina donde las escribes. En esos casos, el código colocado después de la macro no se ejecuta como continuación de esa rutina.

Llamada o familia Retorno incluido Cómo utilizarla
Aliases para sprites: !RenderBox, !Upload, !DXDraw, !PaletteAssignment y los demás aliases de esta categoría. La llamada vuelve y el código continúa después del alias. Escribe el alias directamente, sin anteponer JSR ni JSL. Tu rutina conserva su propio retorno.
GeneralUpload, Upload (macro general) y StandardSpriteUpload. RTS. Coloca la macro al final de una rutina llamada con JSR.
Draw, StandardSpriteDraw y DrawStatic. RTS. Coloca la macro al final de una rutina llamada con JSR.
PaletteAssignment, PaletteAssignmentNoUpload, StandardSpritePaletteAssignment y StandardSpritePaletteAssignmentNoUpload. RTL. Coloca la macro al final de una rutina llamada con JSL.
ReplacePalette, ConcatenateRGBPaletteEffectToGlobal y ConcatenateHSLPaletteEffectToGlobal, en sus versiones de macro general. RTL. Coloca la macro al final de una rutina llamada con JSL.
LoadPaletteIDAndAddress y DefineDynamicSpaceConfig. Ninguno: continúa el código siguiente. Puedes escribir más código después de la macro. Tu rutina debe incluir su propio retorno.
TransferPaletteFromAddress, FromPointer, FromTable, Resource y ResourceWithLength. Ninguno: continúa el código siguiente. Comprueba el carry después de la macro y continúa o termina tu rutina según el resultado.
Macros de preparación de bases, mezcla, transición, DoEffect y conversión, incluidas sus variantes Default. Ninguno: continúa el código siguiente. Puedes encadenar operaciones después de la macro. Las dos macros de concatenación son la excepción indicada arriba.
Macros de transferencia a VRAM y CGRAM, incluidas las variantes Forced, y macros de matemáticas. Ninguno: continúa el código siguiente. Tu rutina debe incluir su propio retorno.
Rutinas del parche DynamicPoseSpaceConfig, TakeDynamicRequest y DynamicRoutine. La rutina llamada retorna con RTL. Utiliza JSL !NombreDeLaRutina. Al volver, se ejecuta la instrucción que sigue al JSL; tu rutina conserva su propio retorno.

Por ejemplo, una rutina que contiene %Upload(...) se llama con JSR PoseManagement y ya termina con el RTS de la macro. Una que contiene %PaletteAssignment(...) se llama con JSL PaletteManagement y ya termina con su RTL. En cambio, !Upload realiza una llamada a la rutina compartida de PIXI y permite continuar después del alias: no es lo mismo que expandir %Upload(...) directamente.

Poses dinámicas

DynamicPoseSpaceConfig

Registros y memoria temporal: entra con A, X e Y en 8 bits. Modifica A y X; conserva Y y los tamaños de los registros. No utiliza scratch. Guarda y restaura DBR alrededor de la selección de configuración. No devuelve un resultado en carry. Se llama con JSL y retorna con RTL.

JSL !DynamicPoseSpaceConfig elige qué partes de la memoria gráfica (VRAM) puede usar Dynamic Xtreme para cargar poses dinámicas. Normalmente se llama desde el init de UberASM al entrar al nivel.

Los defines con las configuraciones disponibles se encuentran en DXDefines.asm, bajo los nombres !DynamicSpaceConfig....

Entrada

  • A de 8 bits: una de las configuraciones !DynamicSpaceConfig... de DXDefines.asm. Sus valores van de $00 a $1C.

Resultado

Después de la llamada, Dynamic Xtreme solo puede elegir espacio dentro de las regiones seleccionadas para cargar poses nuevas. Las poses que ya estaban en VRAM no se eliminan al cambiar esta opción. Lo habitual es configurarla al entrar al nivel, antes de que los sprites soliciten sus gráficos.

Ejemplo

init:
    LDA #!DynamicSpaceConfigSP4
    JSL !DynamicPoseSpaceConfig
RTL

!DynamicSpaceConfigSP4 es una constante publicada en DXDefines.asm que permite utilizar SP4. Otras opciones incluyen !DynamicSpaceConfigSP3, !DynamicSpaceConfigSP34 y !DynamicSpaceConfigSP234. Selecciona una región que no se superponga con los gráficos estáticos utilizados por el nivel.

DefineDynamicSpaceConfig

%DefineDynamicSpaceConfig() permite definir qué espacios de la VRAM pueden utilizarse para poses dinámicas y cuáles quedan restringidos. Se utiliza para crear una configuración propia, en lugar de elegir una de las configuraciones predefinidas de !DynamicPoseSpaceConfig.

Parámetros

%DefineDynamicSpaceConfig(init, end, restricted)
  • init: ID del primer bloque de 16×16 del espacio.
  • end: ID del último bloque de 16×16 del espacio. Ambos extremos se incluyen.
  • restricted: $00 permite utilizar ese espacio para poses dinámicas; $80 lo restringe y el sistema no puede elegirlo para cargar poses.

Los tres parámetros son constantes utilizadas al ensamblar y se escriben sin #. El primer bloque debe ser menor o igual que el último, y ambos deben estar entre $00 y $7F. Por ejemplo, $60 hasta $7F incluye 32 bloques.

Cómo se numeran los bloques

Para esta configuración, el espacio de gráficos de sprites se considera una cuadrícula de 128×256 píxeles. La mitad superior, de 128×128, corresponde a SP1 y SP2; la mitad inferior, también de 128×128, corresponde a SP3 y SP4.

La cuadrícula se divide en bloques de 16×16: hay 8 bloques por fila y 16 filas, para un total de 128 bloques. Sus IDs se numeran de izquierda a derecha y después se continúa en la fila siguiente, de arriba abajo:

Fila de tiles de 16×16 Col. 0 Col. 1 Col. 2 Col. 3 Col. 4 Col. 5 Col. 6 Col. 7
0 $00 $01 $02 $03 $04 $05 $06 $07
1 $08 $09 $0A $0B $0C $0D $0E $0F
2 $10 $11 $12 $13 $14 $15 $16 $17
3 $18 $19 $1A $1B $1C $1D $1E $1F
4 $20 $21 $22 $23 $24 $25 $26 $27
5 $28 $29 $2A $2B $2C $2D $2E $2F
6 $30 $31 $32 $33 $34 $35 $36 $37
7 $38 $39 $3A $3B $3C $3D $3E $3F
8 $40 $41 $42 $43 $44 $45 $46 $47
9 $48 $49 $4A $4B $4C $4D $4E $4F
10 $50 $51 $52 $53 $54 $55 $56 $57
11 $58 $59 $5A $5B $5C $5D $5E $5F
12 $60 $61 $62 $63 $64 $65 $66 $67
13 $68 $69 $6A $6B $6C $6D $6E $6F
14 $70 $71 $72 $73 $74 $75 $76 $77
15 $78 $79 $7A $7B $7C $7D $7E $7F

Cada celda representa un tile de 16×16 y contiene su ID de bloque. Las filas se numeran del 0 al 15 y las columnas del 0 al 7. Estos IDs no son los TileCodes de 8×8 que utiliza el DrawInfo.

Sección Bloques Posición en la cuadrícula
SP1 $00–$1F Primeras cuatro filas.
SP2 $20–$3F Siguientes cuatro filas.
SP3 $40–$5F Siguientes cuatro filas.
SP4 $60–$7F Últimas cuatro filas.

Ejemplos del parche

Estas configuraciones utilizan los mismos rangos que las opciones predefinidas del parche. Colócalas en el init de UberASM, antes de que los sprites soliciten sus poses.

Utilizar solamente SP4:

init:
    ; SP1, SP2 y SP3 restringidos.
    %DefineDynamicSpaceConfig($00, $5F, $80)

    ; SP4 disponible para poses dinámicas.
    %DefineDynamicSpaceConfig($60, $7F, $00)
RTL

Utilizar solamente SP3:

init:
    ; SP1 y SP2 restringidos.
    %DefineDynamicSpaceConfig($00, $3F, $80)

    ; SP3 disponible para poses dinámicas.
    %DefineDynamicSpaceConfig($40, $5F, $00)

    ; SP4 restringido.
    %DefineDynamicSpaceConfig($60, $7F, $80)
RTL

Utilizar SP3 y SP4:

init:
    ; SP1 y SP2 restringidos.
    %DefineDynamicSpaceConfig($00, $3F, $80)

    ; SP3 y SP4 disponibles como un solo espacio.
    %DefineDynamicSpaceConfig($40, $7F, $00)
RTL

Cada ejemplo es una alternativa: utiliza una configuración completa, cubriendo los bloques $00–$7F con espacios consecutivos y sin superponerlos. Restringe los bloques que utilicen el jugador, sprites estáticos u otros recursos cuyos gráficos deban mantenerse. La macro no detecta esos usos por ti.

Registros y resultado

  • A debe estar en modo de 8 bits. La macro modifica A y los flags N/Z; conserva X, Y, carry, DBR y D, y no cambia el tamaño de los registros.
  • Escribe la configuración en DX_Dynamic_Tile_Size y DX_Dynamic_Tile_Offset, en los extremos del espacio indicado. No utiliza scratch.
  • No carga gráficos ni mueve poses que ya estén en VRAM. Utilízala para preparar el espacio al entrar al nivel.
  • No devuelve éxito o fallo en carry y no incluye RTS ni RTL: el código continúa después de cada llamada. El RTL de los ejemplos termina el init de UberASM.

TakeDynamicRequest

Registros y memoria temporal: entra con A de 8 bits y X/Y de 16 bits. Al volver, A, X e Y quedan en 8 bits; sus valores pueden cambiar. X solo es un índice de caché válido si el carry está activado; no conserva el índice del sprite. Puede sobrescribir $00-$0F y $47-$51 al preparar una carga nueva. Conserva DBR y D, tanto en éxito como en fallo. Se llama con JSL y retorna con RTL.

JSL !TakeDynamicRequest recibe el número que identifica una pose y busca sus gráficos en VRAM. Si ya están cargados, marca que siguen en uso para evitar que sean sobrescritos. Si no están, busca espacio y deja preparada su carga para el próximo NMI, el momento entre imágenes en que el juego actualiza los gráficos.

Entrada

  • Y de 16 bits: ID exacto de la pose dinámica.

Resultado

  • Carry activado: los gráficos ya están en VRAM o se programó su carga para el próximo NMI. X contiene el índice de la entrada de caché que guarda su ubicación.
  • Carry desactivado: no hay espacio suficiente en VRAM o cargar la pose superaría el límite de bytes que se pueden transferir durante ese frame.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

RequestPose:
    REP #$10
    LDY #!DynamicPoseIDMySprite000
    JSL !TakeDynamicRequest
    BCC .Unavailable

    ; X contiene el índice hash de la pose solicitada.
    ; Aquí tu código puede guardar ese índice para dibujar la pose.
RTS
.Unavailable
    ; Aquí se maneja la falta de recursos.
RTS

!DynamicPoseIDMySprite000 se genera desde el DynamicInfo y se guarda en DXDefines.asm. El nombre se normaliza en PascalCase eliminando separadores y escribiendo en mayúscula la inicial de cada palabra: my_sprite pasa a MySprite.

Esta llamada devuelve dónde quedaron registrados los gráficos, pero no lo guarda en las variables del sprite ni elige la pose anterior si la solicitud falla. Para ese manejo completo utiliza !Upload.

DynamicRoutine

Registros y memoria temporal: establece A, X e Y en 16 bits para sus cálculos y los deja en 8 bits al volver. Los tres registros pueden cambiar. Puede sobrescribir $00-$0B y $47-$51; PoseIDBackup corresponde a los dos bytes de $02-$03 de la direct page. Conserva D y no cambia DBR: debes preparar el banco de las tablas antes de llamarla. Se llama con JSL y retorna con RTL.

JSL !DynamicRoutine añade a la cola de transferencias la carga de los gráficos de una pose en una posición concreta de VRAM. La copia se realiza durante NMI.

La rutina necesita saber dos cosas: qué pose copiar y dónde colocarla. Recibe el destino en A, pero obtiene el ID de la pose desde una variable interna llamada PoseIDBackup. !TakeDynamicRequest prepara esos datos antes de llamarla.

Datos que necesita la llamada

  • A, en sus 8 bits bajos: posición donde comenzarán los gráficos dentro del mapa de bloques utilizado por el sistema dinámico. La rutina convierte este valor a una dirección de VRAM.
  • PoseIDBackup: variable interna de 16 bits que contiene el ID de la pose que se va a copiar.
  • DBR (registro que selecciona el banco de datos): debe tener el banco donde están las tablas de direcciones y tamaños de las poses.

Antes de llamarla, el código debe haber reservado suficiente espacio en VRAM y comprobado que la carga cabe en el límite de bytes del frame. !TakeDynamicRequest realiza ambas tareas.

Resultado

Lee la dirección y el tamaño de los gráficos de la pose, calcula cómo distribuirlos en el destino y agrega las copias necesarias a la cola de VRAM. A, X e Y quedan en modo de 8 bits. El carry no indica si la operación tuvo éxito.

Ejemplo de funcionamiento

Cuando un sprite solicita una pose que todavía no está en VRAM, !TakeDynamicRequest busca dónde colocarla. Después guarda su ID en PoseIDBackup y llama a !DynamicRoutine con la posición elegida en A. Esta última prepara la copia de los gráficos; el NMI ejecuta la transferencia.

Para cargar una pose desde el código de un sprite, utiliza !Upload. Si necesitas hacer la solicitud directamente mediante su ID, utiliza !TakeDynamicRequest. Llamar a !DynamicRoutine requiere preparar también la variable interna del ID, el banco de datos y el espacio de destino descritos arriba.

GeneralUpload

Registros y memoria temporal: entra con A de 16 bits y X/Y de 8 bits. Al terminar, A, X e Y quedan en 8 bits. A e Y pueden cambiar; con sprite = 1 o 2, X se recupera desde !SpriteIndex; con sprite = 0, no se conserva X. Puede sobrescribir $00-$0F y $47-$51, incluidos los temporales de una solicitud nueva. Conserva DBR y D. Incluye RTS: llama con JSR a la rutina que contiene la macro.


%GeneralUpload() realiza el mismo trabajo de carga que las rutinas para sprites, pero te permite elegir las variables donde guardar el índice de pose, el volteo y la ubicación de sus gráficos. Sirve, por ejemplo, para una entidad que necesita manejar varias poses independientes o para un código que utiliza sus propias tablas.

Parámetros

%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,
    globalFlip, localFlip, lastFlip)

La firma anterior muestra el orden de los parámetros; escribe la llamada en una sola línea.

  • Pose16: 0 utiliza índices de pose de 8 bits; 1 utiliza índices de 16 bits.
  • checkLast: 1 permite seguir dibujando la pose anterior si no se pudo obtener la nueva; 0 desactiva esa opción.
  • sprite: 0 para usar variables propias sin recuperar el índice del sprite; 1 para trabajar con las tablas del sprite, recuperando X desde !SpriteIndex; 2 funciona como 1, pero solicita la pose sin comparar ni cambiar lastPoseIndex.
  • flip: 1 combina globalFlip y localFlip en lastFlip; 0 omite esa actualización.
  • safeCheck: 1 evita repetir la solicitud en el mismo frame utilizando safeLow y safeHigh; 0 omite la comprobación.
  • withoutOffset: 0 suma poseIndex al ID base; 1 utiliza directamente el ID recibido.
  • safeLow y safeHigh: variables que guardan los bytes bajo y alto del frame de la solicitud. Se escriben incluso cuando safeCheck es 0.
  • poseIndex: variable del índice de pose deseado.
  • lastPoseIndex: variable del último índice de pose disponible.
  • lastPoseHashIndex: variable que identifica la entrada donde Dynamic Xtreme guarda la ubicación de los gráficos en VRAM. $FF indica que todavía no hay gráficos disponibles.
  • globalFlip, localFlip y lastFlip: variables del volteo global, local y efectivo.

Entrada adicional

  • A de 16 bits: ID dinámico base o exacto, según withoutOffset.
  • Para sprite = 1 o sprite = 2, !SpriteIndex debe contener el índice del sprite.

Con sprite = 2, la macro solicita la pose aunque poseIndex y lastPoseIndex sean iguales, y deja lastPoseIndex sin modificar. Si consigue los gráficos, guarda su ubicación en lastPoseHashIndex. Si la solicitud falla y checkLast es 1, puede seguir usando los gráficos anteriores. safeCheck sigue controlando si se permite repetir la solicitud durante el mismo frame.

Este valor 2 no cambia el tamaño de los índices. Para utilizar variables de índice de 16 bits se selecciona Pose16 = 1. El ID dinámico entregado en A siempre es de 16 bits.

sprite = 2 suele utilizarse en sprites dinámicos formados por varias piezas, como una cabeza y un cuerpo que necesitan cambiar sus gráficos al mismo tiempo. Al dejar lastPoseIndex sin modificar, permite que el código del sprite coordine el cambio de todas las piezas antes de actualizar el índice de pose. La macro no sincroniza las piezas por sí sola: esa coordinación la realiza el código que la llama.

Resultado

Devuelve el carry activado cuando hay una pose disponible para dibujar: la solicitada o la anterior si checkLast permite conservarla. Si no hay ninguna, devuelve el carry desactivado. Guarda la información de esa pose en las variables indicadas y marca sus gráficos como usados para evitar que sean sobrescritos. La macro incluye un RTS al final; colócala al final de una rutina llamada con JSR.

Ejemplo

PoseManagement:
    REP #$20
    LDA #!DynamicPoseIDMySprite000
    %GeneralUpload(0, 1, 1, 1, 1, 0, "!NormalSafeFrameLowByte,x", "!NormalSafeFrameHighByte,x", "!NormalPoseIndex,x", "!NormalLastPoseIndex,x", "!NormalLastPoseHashIndex,x", "!NormalGlobalFlip,x", "!NormalLocalFlip,x", "!NormalLastFlip,x")

El ejemplo utiliza las tablas de un sprite normal y un índice de pose de 8 bits. !DynamicPoseIDMySprite000 se genera desde el DynamicInfo y queda en DXDefines.asm; el nombre se normaliza en PascalCase eliminando separadores, como my_sprite → MySprite.

Upload (macro general)

Registros y memoria temporal: utiliza el mismo contrato de GeneralUpload, con Pose16 = 0. A entra en 16 bits, X/Y en 8 bits, y los tres quedan en 8 bits. El valor de sprite determina si X vuelve a cargarse desde !SpriteIndex. La macro incluye RTS.

%Upload() es la variante de %GeneralUpload() para índices de pose de 8 bits. No debe confundirse con el alias para sprites !Upload.

Parámetros

%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,
    safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,
    globalFlip, localFlip, lastFlip)

Recibe los mismos datos que %GeneralUpload(), pero los índices guardados en las variables siempre son de 8 bits. La macro ya incluye el RTS que termina la rutina.

El parámetro sprite también admite 2: omite la comparación con lastPoseIndex y no actualiza esa variable, pero sí actualiza lastPoseHashIndex al obtener la pose. No habilita índices de 16 bits; para eso se utiliza %GeneralUpload() con Pose16 = 1.

Este modo suele usarse para coordinar sprites dinámicos con varias piezas y hacer que cambien sus gráficos al mismo tiempo. Por ejemplo, el código puede manejar por separado la carga de la cabeza y del cuerpo, y actualizar el índice de pose cuando corresponda cambiar ambas partes juntas. Como la macro deja lastPoseIndex sin modificar, el código del sprite puede controlar ese cambio.

Ejemplo

PoseManagement:
    REP #$20
    LDA #!DynamicPoseIDMySprite000
    %Upload(1, 1, 1, 1, 0, "!NormalSafeFrameLowByte,x", "!NormalSafeFrameHighByte,x", "!NormalPoseIndex,x", "!NormalLastPoseIndex,x", "!NormalLastPoseHashIndex,x", "!NormalGlobalFlip,x", "!NormalLocalFlip,x", "!NormalLastFlip,x")

!DynamicPoseIDMySprite000 es generado desde el DynamicInfo y se guarda en DXDefines.asm. El nombre usa PascalCase eliminando separadores: my_sprite pasa a MySprite.

StandardSpriteUpload

Registros y memoria temporal: utiliza el contrato de GeneralUpload con sprite = 1. A entra en 16 bits y X/Y en 8 bits. Al volver, X contiene !SpriteIndex; A e Y pueden cambiar y los tres quedan en 8 bits. Comparte sus scratch y termina con RTS.

%StandardSpriteUpload(withoutOffset, type) selecciona automáticamente las tablas de Dynamic Xtreme correspondientes a un sprite normal, cluster o extended. Es la macro utilizada por las rutinas PIXI de carga.

Parámetros y entradas

  • withoutOffset: 0 suma !PoseIndex al ID base; 1 utiliza el ID exacto.
  • type: "Normal", "Cluster" o "Extended".
  • A de 16 bits: ID dinámico.
  • !SpriteIndex: índice del sprite.
  • Tablas de poses y volteo de Dynamic Xtreme del tipo seleccionado, inicializadas como en las rutinas !Upload.

Resultado

Selecciona las variables del tipo de sprite indicado. Permite conservar la pose anterior si la nueva no está lista, actualiza el volteo y evita repetir la solicitud durante el mismo frame. El carry funciona igual que en !Upload. La macro ya incluye el RTS que termina la rutina.

Ejemplo

PoseManagement:
    REP #$20
    LDA #!DynamicPoseIDMySprite000
    %StandardSpriteUpload(0, "Normal")

!DynamicPoseIDMySprite000 se genera desde el DynamicInfo y queda en DXDefines.asm. El nombre se normaliza en PascalCase: my_sprite pasa a MySprite, eliminando los separadores.

Dibujo de poses

Las macros de esta categoría terminan la rutina que las contiene mediante RTS. Los ejemplos deben llamarse con JSR. A debe contener el ID de dibujo con 16 bits; !PropParam ($52) y !MaxTilePriorityParam ($0A) se preparan igual que para !DXDraw.

Draw

Registros y memoria temporal: entra con A de 16 bits y X/Y de 8 bits. A e Y pueden cambiar. Con sprite = 1, X se recupera desde !SpriteIndex al preparar un dibujo válido; con sprite = 0, no se conserva el X inicial. Si no hay pose válida, X no cambia. Los tres registros quedan en 8 bits. Puede sobrescribir $00-$0F, $45-$4F y $8A; con offset = 1, también $8B-$8C. Conserva DBR y D. Incluye RTS.

%Draw() dibuja una pose dinámica. En la llamada indicas qué gráficos usar, su paleta, su volteo y la posición donde quieres dibujarla.

Parámetros

%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)
  • offset: 0 utiliza las coordenadas entregadas; 1 añade !XOffsetParam ($8A) y !YOffsetParam ($8B), de 8 bits con signo.
  • sprite: 1 recupera el índice del sprite en X desde !SpriteIndex antes de leer su paleta y posición; 0 omite ese paso.
  • lastPoseHashIndex: variable que identifica dónde están registrados los gráficos de la pose en Dynamic Xtreme. Si contiene $FF, no se dibuja.
  • lastFlip: variable o valor que indica el volteo con el que se dibujará.
  • palette: variable o valor de la paleta; $00 selecciona la 8, $02 la 9, y así hasta $0E para la F.
  • xl y xh: variables o valores de los bytes bajo y alto de la posición X.
  • yl y yh: variables o valores de los bytes bajo y alto de la posición Y.

Resultado

Dibuja la pose con los gráficos indicados por lastPoseHashIndex, en la posición X e Y entregada. Puedes pasar las variables de posición de un sprite o indicar otra posición para dibujar desde UberASM u otro código.

Ejemplo

DrawPose:
    LDA #$20
    STA !PropParam
    LDA #$02
    STA !MaxTilePriorityParam
    REP #$20
    LDA #!PoseIDMySprite_Frame0
    %Draw(0, 1, "!NormalLastPoseHashIndex,x", "!NormalLastFlip,x", "!NormalPalette,x", "!SpriteXLow,x", "!SpriteXHigh,x", "!SpriteYLow,x", "!SpriteYHigh,x")

!PoseIDMySprite_Frame0 se genera desde el DrawInfo y se guarda en DXDefines.asm. Los nombres se normalizan en PascalCase eliminando separadores, como my_sprite → MySprite. El ID debe corresponder a los gráficos dinámicos disponibles.

StandardSpriteDraw

Registros y memoria temporal: comparte el contrato y las scratch de Draw, con sprite = 1. Entra con A de 16 bits y X/Y de 8 bits. Prepara X con el índice del sprite antes de invocarla, porque lee su índice hash antes de recuperar !SpriteIndex. Al terminar deja los tres registros en 8 bits e incluye RTS.

%StandardSpriteDraw(offset, type) dibuja una pose dinámica utilizando las tablas de Dynamic Xtreme del tipo de sprite seleccionado.

Parámetros y entradas

  • offset: 0 sin desplazamiento adicional; 1 utiliza los offsets de $8A y $8B.
  • type: "Normal", "Cluster" o "Extended".
  • A de 16 bits: ID de dibujo.
  • !SpriteIndex: índice del sprite.
  • !PropParam y !MaxTilePriorityParam: propiedades y prioridad.
  • Las tablas de paleta, último volteo e índice hash de Dynamic Xtreme del tipo seleccionado.

Resultado

El mismo que %Draw(), utilizando las tablas estándar. Es la macro que utilizan las rutinas PIXI !DXDraw y !DXDrawWithOffset.

Para sprites normales, las rutinas PIXI preparan los aliases de coordenadas !NormalXLow, !NormalXHigh, !NormalYLow y !NormalYHigh. Si se expande la macro directamente, también deben estar definidos, como en este ejemplo.

Ejemplo

!NormalXLow = !SpriteXLow
!NormalXHigh = !SpriteXHigh
!NormalYLow = !SpriteYLow
!NormalYHigh = !SpriteYHigh

DrawPose:
    LDA #$20
    STA !PropParam
    LDA #$02
    STA !MaxTilePriorityParam
    REP #$20
    LDA #!PoseIDMySprite_Frame0
    %StandardSpriteDraw(0, "Normal")

!PoseIDMySprite_Frame0 se genera desde el DrawInfo y queda en DXDefines.asm. Su nombre usa PascalCase eliminando separadores: my_sprite se convierte en MySprite.

DrawStatic

Registros y memoria temporal: entra con A de 16 bits y X/Y de 8 bits. A e Y pueden cambiar; X se conserva, pero los tres registros quedan en 8 bits. Puede sobrescribir $00-$0F, $45-$4F y $8A; con offset = 1, también $8B-$8C. El parámetro sprite no recupera X desde !SpriteIndex en esta macro. Conserva DBR y D. Incluye RTS.

%DrawStatic() dibuja una pose estática, declarada con .IsStatic en el DrawInfo. Sus gráficos deben estar previamente cargados en las posiciones de VRAM indicadas por sus tiles.

Parámetros

%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)
  • offset: 0 sin desplazamiento adicional; 1 utiliza !XOffsetParam ($8A) y !YOffsetParam ($8B), con signo.
  • sprite: parámetro conservado en la firma; la implementación actual de esta macro no lo utiliza.
  • lastFlip: variable o valor que indica el volteo; #$00 dibuja sin volteo.
  • palette: variable o valor de paleta: #$00 selecciona la 8, #$02 la 9, y así hasta #$0E para la F.
  • xl y xh: variables o valores de los bytes bajo y alto de la posición X.
  • yl y yh: variables o valores de los bytes bajo y alto de la posición Y.

Entradas adicionales

  • A de 16 bits: ID de dibujo estático.
  • !PropParam ($52) y !MaxTilePriorityParam ($0A): propiedades y prioridad.
  • !Tile ($05): número de tile, cuando todos los tiles de la pose están definidos con el valor predeterminado 0. Si el DrawInfo declara otros valores, utiliza esos tiles directamente.

Resultado

Dibuja la pose sin consultar la caché de gráficos dinámicos. No requiere !LastPoseHashIndex ni una llamada previa a !Upload.

Ejemplo

DrawPose:
    LDA #$80
    STA !Tile
    LDA #$20
    STA !PropParam
    LDA #$02
    STA !MaxTilePriorityParam
    REP #$20
    LDA #!PoseIDMyStaticSprite_Frame0
    %DrawStatic(0, 1, #$00, #$04, "!SpriteXLow,x", "!SpriteXHigh,x", "!SpriteYLow,x", "!SpriteYHigh,x")

El ejemplo utiliza el tile $80 si la pose está configurada para tomarlo desde !Tile, sin volteo y con la paleta A. !PoseIDMyStaticSprite_Frame0 se genera desde el DrawInfo y queda en DXDefines.asm. Su nombre usa PascalCase eliminando separadores y poniendo en mayúscula la inicial de cada palabra: my_static_sprite pasa a MyStaticSprite.

Paletas

Estas macros permiten elegir qué paleta usa un sprite, cargar sus colores y cambiarlos durante el juego.

LoadPaletteIDAndAddress

Registros y memoria temporal: entra con A de 8 bits; la macro establece los tamaños que necesita para calcular las direcciones. Modifica A y X. Y no se utiliza, pero pasa a modo de 8 bits y pierde su byte alto si antes estaba en 16 bits. Al terminar los tres registros quedan en 8 bits. Escribe $00-$04 y lee $0E-$0F. Conserva DBR y D; carry no es un indicador de éxito. La expansión continúa en la instrucción siguiente.

%LoadPaletteIDAndAddress() permite saber qué número identifica una paleta y dónde están guardados sus colores en la ROM. Elige una de las paletas del DynamicInfo: 0 para la primera, 1 para la segunda, etc. La llamada no carga colores en el juego; solo te entrega esos datos para usarlos después.

Entradas

  • A de 8 bits: índice de la paleta dentro del DynamicInfo.
  • $0E-$0F: guarda aquí el define !MySpritePaletteTableOffset de tu DynamicInfo, con 16 bits, como muestra el ejemplo.

Resultado

  • $00-$01: ID de la paleta.
  • $02-$04: dirección de sus colores en ROM, en formato BGR555.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

    REP #$20
    LDA #!MySpritePaletteTableOffset
    STA $0E
    SEP #$20

    LDA #$01            ; Segunda paleta del DynamicInfo
    %LoadPaletteIDAndAddress()
    ; $00-$01 contiene su ID y $02-$04 su dirección ROM.

En PIXI también puede llamarse mediante %DXLoadPaletteIDAndAddress(), con las mismas entradas y resultados. Esta variante llama a una rutina compartida y después continúa con el código siguiente.

!MySpritePaletteTableOffset se genera desde el DynamicInfo y queda en DXDefines.asm. El nombre se normaliza eliminando espacios, guiones bajos y guiones, y poniendo en mayúscula la inicial de cada palabra: my_sprite pasa a MySprite.

PaletteAssignment (macro general)

Registros y memoria temporal: entra con X/Y de 8 bits y A de 16 bits cuando PalettesChange está habilitado. Si está deshabilitado, entra con A de 8 bits y no se utiliza el offset de tabla. A e Y pueden cambiar; con sprite = 1, X se recupera desde !SpriteIndex cuando se utiliza internamente; con sprite = 0, no se conserva X. Al volver, los tres quedan en 8 bits. Puede sobrescribir $00-$0F, $D5 y los temporales de efectos cuando corresponda. Conserva DBR y D. La macro termina con RTL.

%PaletteAssignment() asigna y carga una paleta igual que !PaletteAssignment, pero permite indicar las variables donde se guardan sus opciones y su estado. Se puede usar para manejar una paleta adicional de un sprite o para un código con variables propias.

Si la paleta ya estaba asignada, mantiene su temporizador de uso en 2 para que no sea reemplazada mientras se utiliza. Si el bit $80 de las opciones está activado, también aplica el efecto global correspondiente.

Parámetros

%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)
  • sprite: 1 utiliza !SpriteIndex para acceder a las tablas del sprite; 0 permite usar variables independientes del índice del sprite.
  • palette: variable que recibe la paleta asignada. Debe comenzar en $FF. Los valores $00, $02, ..., $0E corresponden a las paletas 8-F.
  • paletteAssignment: variable o valor con formato --AA----. $00 permite que Dynamic Xtreme elija el destino y cargue los colores; $10 utiliza el destino que tú indicas y carga los colores; $20 utiliza ese destino con los colores que ya tiene el nivel.
  • paletteOption: variable o valor con formato EPPP----. E = 1 permite aplicar el efecto global; E = 0 lo excluye. En modo manual, PPP elige entre la paleta 8 (000) y la F (111). En automático, 000 permite todas, 0XX distinto de cero permite 8-B y 1XX permite C-F. Los cuatro bits bajos no se usan para estas opciones.
  • paletteVersion: variable o valor que selecciona una paleta de la lista del DynamicInfo: 0 para la primera, 1 para la segunda, etc. En las rutinas de sprites corresponde a !Version,x.
  • paletteLastVersion: variable que guarda la última versión procesada. Debe comenzar en $FF.
  • manualIDGroup y manualID: juntos forman el número con el que el sistema reconoce la paleta en los modos manuales. El primero indica el grupo: #$FE para normal, #$FC para cluster y #$FD para extended. El segundo indica el tipo de sprite; en uno normal se utiliza !CustomSpriteNumber,x, como en el ejemplo.

También puedes crear grupos propios: por ejemplo, usar manualIDGroup = #$FB para el jugador y #$FA para otro tipo de entidad. Son ejemplos, no valores predefinidos de Dynamic Xtreme. Elige valores que no estés utilizando para otro grupo y usa manualID para distinguir los recursos dentro de cada uno. Los grupos $FE, $FD y $FC ya son utilizados por las rutinas de sprites normales, extended y cluster, respectivamente.

Entrada adicional

  • A de 16 bits: el define !MySpritePaletteTableOffset del DynamicInfo que contiene las paletas.
  • Si sprite = 1, !SpriteIndex debe contener el índice del sprite.

Resultado

  • Carry activado: hay una paleta con la que se puede dibujar; desactivado si todavía no hay ninguna.
  • Guarda el número de paleta en palette y actualiza paletteLastVersion cuando procesa la versión.
  • A, X e Y quedan en modo de 8 bits.

Ejemplo

PaletteManagement:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    %PaletteAssignment(1, "!NormalPalette,x", "!NormalPaletteAssignment,x", "!NormalPaletteOption,x", "!NormalVersion,x", "!NormalLastVersion,x", #$FE, "!CustomSpriteNumber,x")

El ejemplo utiliza las variables de un sprite normal. !MySpritePaletteTableOffset se genera desde el DynamicInfo y queda en DXDefines.asm. El nombre se normaliza en PascalCase eliminando separadores: my_sprite se convierte en MySprite.

Llama a la rutina del ejemplo con JSL PaletteManagement. La macro ya incluye el RTL que termina la rutina, por lo que no debes añadir código después de ella.

PaletteAssignmentNoUpload (macro general)

Registros y memoria temporal: comparte el contrato de PaletteAssignment (macro general). Además de su carry, devuelve Y como se indica abajo; no conserves en Y otro dato que necesites después. Las salidas de $00-$04 solo son válidas si se leyó una paleta del DynamicInfo. Termina con RTL.

%PaletteAssignmentNoUpload() elige una paleta como %PaletteAssignment(), pero deja pendiente la carga de sus colores. Permite aplicar después un efecto local y combinarlo con el global.

Parámetros y entradas

%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)

Los parámetros son los mismos que en %PaletteAssignment(). A recibe el offset de la tabla con 16 bits. palette y paletteLastVersion deben comenzar en $FF.

paletteVersion elige los colores de la lista del DynamicInfo: 0 para la primera paleta, 1 para la segunda, etc. paletteAssignment decide el modo: $00 automático, $10 manual y $20 manual sin cargar colores. paletteOption utiliza EPPP----: E permite el efecto global y PPP selecciona la paleta 8-F en manual. En automático, 000 permite todas, 0XX distinto de cero permite 8-B y 1XX permite C-F. Para aplicar después un efecto local sobre los colores del DynamicInfo, utiliza el modo automático o manual con carga.

Resultado

  • Carry activado: hay una paleta asignada; desactivado si no pudo obtenerse.
  • palette: número de la paleta asignada, de dos en dos entre $00 y $0E.
  • paletteLastVersion: última versión procesada.
  • $00-$01: ID de la paleta seleccionada del DynamicInfo.
  • $02-$04: dirección ROM de sus colores.
  • Y = 1 indica que se acaba de asignar la paleta y hay que calcular su efecto. Y = 0 indica que no hace falta recalcularlo por una asignación nueva.
  • A, X e Y quedan en modo de 8 bits.

Usa los datos de $00-$04 solo cuando la llamada leyó una paleta del DynamicInfo. Si usas una paleta del nivel sin cargarla, deshabilitaste los cambios de paleta o la llamada no se procesa en el modo de juego actual, esas direcciones pueden contener datos de otro código.

Ejemplo

AssignPaletteForEffect:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    %PaletteAssignmentNoUpload(1, "!NormalPalette,x", "!NormalPaletteAssignment,x", "!NormalPaletteOption,x", "!NormalVersion,x", "!NormalLastVersion,x", #$FE, "!CustomSpriteNumber,x")

Después de llamar a AssignPaletteForEffect con JSL, comprueba el carry y aplica el efecto usando los datos devueltos. Conserva Y y $02-$04 para la llamada de concatenación.

La macro ya termina la rutina con RTL. El código que aplica el efecto va después de la llamada JSL AssignPaletteForEffect, no después de la macro dentro de esa rutina.

!MySpritePaletteTableOffset se genera desde el DynamicInfo y queda en DXDefines.asm. Su nombre usa PascalCase eliminando separadores: my_sprite pasa a MySprite.

StandardSpritePaletteAssignment

Registros y memoria temporal: comparte el contrato de PaletteAssignment (macro general), con sprite = 1. Entra con X preparado para leer las tablas del sprite y con !SpriteIndex correspondiente al mismo sprite. Recupera X desde ese índice cuando lo utiliza internamente; A e Y pueden cambiar. Incluye RTL.

%StandardSpritePaletteAssignment() utiliza las variables de paleta del tipo de sprite indicado. Es la macro utilizada por las rutinas PIXI de asignación.

Parámetros y entradas

%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)
  • type: "Normal", "Cluster" o "Extended".
  • manualIDGroup: #$FE para normal, #$FC para cluster o #$FD para extended.
  • También puedes elegir un grupo propio, por ejemplo #$FB para el jugador o #$FA para otro tipo de entidad, siempre que esos valores no estén siendo utilizados por otro grupo de tu proyecto.
  • manualID: variable o valor que identifica el tipo de sprite en los modos manuales.
  • A de 16 bits: el define !MySpritePaletteTableOffset del DynamicInfo que contiene las paletas.
  • !SpriteIndex: índice del sprite.
  • Las variables de Dynamic Xtreme para paleta, opciones, versión y última versión del tipo seleccionado, preparadas como en !PaletteAssignment.

Resultado

El mismo que !PaletteAssignment: guarda la paleta asignada en la tabla del sprite y devuelve el carry activado cuando se puede dibujar con ella.

La macro ya incluye un RTL. Llama a la rutina del ejemplo con JSL PaletteManagement y no añadas código después de la macro.

Ejemplo

PaletteManagement:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    %StandardSpritePaletteAssignment("Normal", #$FE, "!CustomSpriteNumber,x")

!MySpritePaletteTableOffset se genera desde el DynamicInfo y queda en DXDefines.asm. El nombre se normaliza en PascalCase: my_sprite pasa a MySprite al eliminar los separadores.

StandardSpritePaletteAssignmentNoUpload

Registros y memoria temporal: comparte el contrato de PaletteAssignmentNoUpload (macro general), con sprite = 1. X y !SpriteIndex deben identificar al mismo sprite al entrar. Conserva Y y $02-$04 de su resultado si vas a concatenar un efecto. Incluye RTL.

%StandardSpritePaletteAssignmentNoUpload() utiliza las variables del tipo de sprite seleccionado para asignar la paleta, dejando pendiente la carga de los colores.

Parámetros y entradas

%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)

Recibe los mismos parámetros y datos que %StandardSpritePaletteAssignment(). A debe contener el offset de la tabla de paletas con 16 bits.

Resultado

El mismo que !PaletteAssignmentNoUpload: guarda la paleta asignada y devuelve el carry, Y, el ID en $00-$01 y la dirección en $02-$04, con las condiciones indicadas en esa entrada.

La macro ya incluye un RTL. Llama a la rutina del ejemplo con JSL AssignPaletteForEffect. El código que aplica el efecto va después de esa llamada.

Ejemplo

AssignPaletteForEffect:
    REP #$20
    LDA #!MySpritePaletteTableOffset
    %StandardSpritePaletteAssignmentNoUpload("Normal", #$FE, "!CustomSpriteNumber,x")

!MySpritePaletteTableOffset se genera desde el DynamicInfo y queda en DXDefines.asm. Su nombre se normaliza en PascalCase eliminando separadores: my_sprite se convierte en MySprite.

ReplacePalette (macro general)

Registros y memoria temporal: entra con A, X e Y de 8 bits y con el puntero de origen preparado en $02-$04. A e Y pueden cambiar; con sprite = 1, X se recupera desde !SpriteIndex; con sprite = 0, no se conserva X. Los tres quedan en 8 bits. Puede sobrescribir $00-$01 y los temporales de efectos cuando corresponda. Conserva DBR y D. Termina con RTL.

%ReplacePalette() sustituye los colores de una paleta que ya estás usando. Hace lo mismo que !ReplacePalette, pero tú eliges qué variables leer. Si otros sprites o códigos usan esa misma paleta, también verán los nuevos colores.

Suele utilizarse después de una asignación sin carga, como %PaletteAssignmentNoUpload(). Primero obtienes la paleta asignada y después preparas en $02-$04 la dirección de los colores que quieres usar para reemplazarla.

Parámetros y entradas

%ReplacePalette(sprite, paletteOption, palette)
  • sprite: 1 obtiene el índice del sprite desde !SpriteIndex; 0 utiliza variables independientes de ese índice.
  • paletteOption: variable o valor de las opciones de paleta. El bit $80 indica si se aplica el efecto global.
  • palette: variable o valor de la paleta de destino, entre $00 y $0E de dos en dos.
  • $02-$04: dirección ROM de los nuevos colores en BGR555.
  • A en modo de 8 bits.

Resultado

Cambia los colores sin cambiar el ID de asignación. Devuelve el carry activado cuando hay colores con los que se puede dibujar, incluidos los anteriores si el cambio todavía no se pudo completar. El carry queda desactivado si todavía no hay un resultado disponible.

Llámala cuando cambien los colores que quieres mostrar. Repetir la llamada cada frame obliga a preparar de nuevo la paleta y sus efectos.

Llama a la rutina del ejemplo con JSL ReplaceSpritePalette. La macro ya incluye el RTL que termina la rutina.

Ejemplo

ReplaceSpritePalette:
    LDA.b #!PaletteMyAlternatePalette
    STA $02
    LDA.b #!PaletteMyAlternatePalette>>8
    STA $03
    LDA.b #!PaletteMyAlternatePalette>>16
    STA $04
    %ReplacePalette(1, "!NormalPaletteOption,x", "!NormalPalette,x")

!PaletteMyAlternatePalette es la dirección de una paleta insertada a partir de los recursos del DynamicInfo y queda en DXDefines.asm. Su nombre se normaliza eliminando separadores y poniendo en mayúscula la inicial de cada palabra: my_alternate_palette pasa a MyAlternatePalette.

Cargar colores con TransferPalette

Estas macros cargan colores en la paleta que tú elijas, sin asignación automática. Puedes usarlas para cambiar una paleta de fondo, una paleta reservada para un sprite o colores preparados en RAM.

A diferencia de las macros de transferencia de PPU, también actualizan las copias de colores que necesita el juego y preparan el estado de los efectos. No hace falta copiar los buffers ni invalidar sus indicadores a mano.

Parámetros comunes

  • CGRAMOffset: primer color que se cambiará, entre $00 y $FF. Es un operando de 8 bits: #$91 empieza en el color 1 de la paleta 9; $00 utiliza el número guardado en esa scratch.
  • Length: cantidad de bytes que se copiarán. Es un valor conocido al ensamblar, sin #: $001E copia 15 colores. Debe ser mayor que cero y par, y la carga no debe pasar del último color de CGRAM.
  • GlobalEffect: utiliza 0 para cargar sin efecto global o 1 para que la paleta reciba el efecto global. Es una opción fija de la llamada, no una variable de RAM.

Qué hace GlobalEffect

Valor Comportamiento
0 Programa la transferencia de los colores sin efecto y actualiza los buffers de SMW y Dynamic Xtreme. Si los efectos están habilitados, excluye del efecto global las paletas modificadas.
1 Guarda los colores originales para que el sistema les aplique el efecto global antes de cargarlos. Registra las paletas modificadas para recibirlo y borra los indicadores de sus efectos anteriores.

Con GlobalEffect = 1 no se carga primero una versión sin efecto: se espera al resultado del sistema de efectos. Esto también sirve para dejar preparada una paleta cuando el ID del efecto global todavía es 0. Si los efectos de paleta están deshabilitados en la instalación, la llamada utiliza la carga directa.

Estas opciones afectan a cada paleta de 16 colores que toque la carga, no solo a los colores copiados. Para una carga con efecto global, proporciona todos los colores visibles de las paletas que cambies: por ejemplo, los 15 colores de una paleta de sprites, comenzando en su color 1. No uses una carga parcial para conservar otros colores originales que todavía no hayas preparado.

Entradas y resultado comunes

  • Entra con A, X e Y en modo de 8 bits. D debe ser $0000 en LoROM o $3000 en el contexto habitual de SA-1 Pack. DBR debe permitir acceder al buffer de paletas de SMW: $0703 en LoROM o su espejo $6703 en SA-1. Los bancos habituales con espejos de RAM, como $00-$3F y $80-$BF, permiten esos accesos. Si pasas tablas con direcciones de 16 bits, DBR también debe permitir leerlas.
  • Carry activado: la transferencia directa fue aceptada o los colores originales quedaron preparados para el efecto global. En este último caso, no significa que el resultado ya se haya cargado a pantalla.
  • Carry desactivado: no se aceptó la transferencia directa por el límite de datos del frame. Puedes volver a intentarlo más adelante; no se actualizan los buffers ni los indicadores de efectos de esa carga.
  • A y X pueden cambiar, tanto en éxito como en fallo. Y puede cambiar si se copian colores; no lo utilices para conservar otro dato entre llamadas. Los tres quedan en modo de 8 bits en ambos resultados. Conservan DBR y D.
  • Las llamadas pueden modificar $68-$6D cuando están habilitados los efectos; las variantes FromAddress, FromTable y Resource, incluida ResourceWithLength, también utilizan $65-$67. No coloques el puntero de origen ni el color de destino en scratch que la propia llamada vaya a sobrescribir antes de terminar de utilizarlos.
  • No incluyen RTS ni RTL: el código continúa después de la macro.

Si el origen está en RAM, conserva sus datos hasta que se ejecute la transferencia programada. El bloque de origen tampoco debe cruzar el final de su banco. Para CGRAMOffset, utiliza un inmediato o una variable que siga siendo válida después de que la macro cambie X e Y; evita operandos indexados con esos registros.

Llama a estas macros cuando quieras cambiar los colores, no en cada frame si la paleta sigue siendo la misma. Si utilizas una paleta de sprites con un destino fijo, resérvala para que la asignación automática no la utilice.

TransferPaletteFromAddress

%TransferPaletteFromAddress() carga colores desde una dirección conocida al ensamblar. Puede ser un label de tu código o un define con la dirección completa del recurso.

Parámetros

%TransferPaletteFromAddress(Address, CGRAMOffset, Length, GlobalEffect)

Ejemplo

    ; Paleta 9, colores 1-F, con efecto global.
    %TransferPaletteFromAddress(!PaletteMyPalette, #$91, $001E, 1)

!PaletteMyPalette se genera al instalar una paleta declarada en Palettes de un DynamicInfo y queda en DXDefines.asm. El nombre usa PascalCase: se eliminan espacios, guiones bajos y guiones, y se pone en mayúscula la inicial de cada palabra. Por ejemplo, my_palette pasa a MyPalette.

TransferPaletteFromPointer

%TransferPaletteFromPointer() utiliza una dirección de origen que ya está guardada en tres bytes consecutivos de scratch. Es útil si tu código elige la paleta durante el juego.

Parámetros

%TransferPaletteFromPointer(Pointer, CGRAMOffset, Length, GlobalEffect)
  • Pointer: dirección del primer byte de la scratch, sin #. Los tres bytes deben contener la dirección de origen en orden bajo, alto y banco. Por ejemplo, $02 utiliza $02-$04.
  • Los demás parámetros y el carry funcionan como se explica en Cargar colores con TransferPalette.

Ejemplo

    ; Preparar la dirección de la paleta en $02-$04.
    REP #$20
    LDA.w #!PaletteMyPalette
    STA $02
    SEP #$20
    LDA.b #!PaletteMyPalette>>16
    STA $04

    ; Paleta 9, colores 1-F, sin efecto global.
    %TransferPaletteFromPointer($02, #$91, $001E, 0)

!PaletteMyPalette se genera desde una paleta del DynamicInfo y queda en DXDefines.asm. Su nombre se normaliza en PascalCase eliminando separadores: my_palette se convierte en MyPalette.

TransferPaletteFromTable

%TransferPaletteFromTable() permite indicar por separado los dos bytes de dirección y el byte de banco del origen. Puedes obtenerlos de tablas, variables o valores inmediatos. La macro reúne esos datos en $65-$67.

Parámetros

%TransferPaletteFromTable(TableAddr, TableBNK, CGRAMOffset, Length, GlobalEffect)
  • TableAddr: operando que se lee con A de 16 bits para obtener los dos bytes de dirección.
  • TableBNK: operando que se lee con A de 8 bits para obtener el banco.
  • Los demás parámetros y el carry funcionan como se explica en Cargar colores con TransferPalette.

Ejemplo

    ; $02-$03 contiene la dirección y $04 contiene el banco.
    %TransferPaletteFromTable("$02", "$04", #$91, $001E, 1)

A diferencia de FromPointer, los operandos de dirección y banco no tienen que estar en posiciones consecutivas. Si los lees desde tablas del código, el banco de datos debe permitir acceder a ellas.

TransferPaletteResource

%TransferPaletteResource() carga una paleta registrada en el DynamicInfo utilizando su tamaño completo. No necesitas escribir su dirección ni su cantidad de bytes.

Parámetros

%TransferPaletteResource(Name, CGRAMOffset, GlobalEffect)
  • Name: nombre normalizado de la paleta, sin prefijo !Palette y sin extensión. La macro utiliza !Palette<Name> y !Palette<Name>Size.
  • Los demás parámetros y el carry funcionan como se explica en Cargar colores con TransferPalette.

Ejemplo

    ; MyPalette contiene 15 colores.
    %TransferPaletteResource(MyPalette, #$91, 1)
    BCS .Accepted
    ; No se aceptó la carga directa: volver a intentarlo después.
    RTL
.Accepted
    ; Continuar con el resto del código.

El ejemplo continúa en .Accepted si se aceptó la carga directa o se prepararon los colores para el efecto global. El RTL pertenece al ejemplo, no a la macro.

MyPalette corresponde a los defines !PaletteMyPalette y !PaletteMyPaletteSize, generados en DXDefines.asm desde la sección Palettes del DynamicInfo. El nombre usa PascalCase eliminando espacios, guiones bajos y guiones: my_palette pasa a MyPalette. Esta llamada no utiliza los defines !Resource... de la sección Resources ni las paletas convertidas RGB/HSL de un *.paleffect.

TransferPaletteResourceWithLength

%TransferPaletteResourceWithLength() utiliza la dirección de una paleta registrada, pero permite copiar solo la cantidad de bytes que indiques.

Parámetros

%TransferPaletteResourceWithLength(Name, CGRAMOffset, Length, GlobalEffect)
  • Name: nombre normalizado de la paleta, igual que en %TransferPaletteResource().
  • Length: cantidad de bytes que se copiarán, sin #. No debe superar el tamaño del recurso.
  • Los demás parámetros y el carry funcionan como se explica en Cargar colores con TransferPalette.

Ejemplo

    ; Copiar 4 colores al comienzo de la paleta 9, sin efecto global.
    %TransferPaletteResourceWithLength(MyPalette, #$90, $0008, 0)

MyPalette utiliza el define !PaletteMyPalette, generado desde una paleta del DynamicInfo y publicado en DXDefines.asm. El nombre se normaliza en PascalCase eliminando separadores: my_palette se convierte en MyPalette.

TransferPaletteCommon y TransferPaletteData son las partes internas que comparten estas llamadas. Para cargar paletas desde tu código, utiliza las variantes anteriores, que también preparan el estado de los efectos.

Efectos de paleta

Estas macros permiten modificar los colores de una paleta: teñirla, cambiar su brillo, pasar de una paleta a otra o aplicar un efecto guardado en un archivo *.paleffect.

Para ver ejemplos completos, consulta Aplicar un efecto global de paleta en la guía de UberASM, con ejemplos de un efecto fijo, un ciclo y una transición. El apartado Cambiar paletas durante el juego muestra cómo cargar los colores con TransferPalette y comprobar si la llamada fue aceptada.

RGB trabaja con rojo, verde y azul. HSL trabaja con tono, saturación y luminosidad. Elige las macros RGB o HSL según el cambio que quieras realizar. Para conocer los efectos disponibles, consulta Tipos de efectos.

¿Qué llamada necesitas?

Quieres… Utiliza…
Teñir una paleta o cambiar su tono, saturación o luminosidad. Mix / MixAndMerge.
Pasar de una paleta a otra. PaletteTransition.
Aplicar un efecto que ya definiste en un archivo *.paleffect. DoEffect / DoEffectAndMerge.
Darle un efecto propio a un sprite y conservar además el efecto global. ConcatenateRGBPaletteEffectToGlobal o su variante HSL, después de asignar la paleta sin carga.

Para calcular un efecto directamente, el proceso habitual es preparar los colores originales con SetRGBBase o SetHSLBase y después aplicar el cambio. Los ejemplos utilizan las variantes Default, que trabajan con las copias de paleta de Dynamic Xtreme y evitan escribir direcciones de memoria.

Las variantes AndMerge dejan los colores en el formato que necesita SNES para mostrarlos. Aun así, calcularlos no los envía automáticamente a la pantalla: la carga se completa mediante el manejo de paletas o las transferencias a CGRAM. Si estás usando las rutinas de concatenación después de PaletteAssignmentNoUpload, estas ya se encargan de preparar los colores y completar su carga.

En los ejemplos, prepara A en modo de 8 bits antes de llamar a las macros.

Registros y memoria temporal de los efectos

  • Las macros de preparación de bases, mezcla, transición, conversión y DoEffect entran con A, X e Y de 8 bits. Sus variantes Default utilizan el mismo contrato. Las macros de concatenación tienen una entrada diferente, descrita en su apartado.
  • Las macros anteriores preparan sus argumentos y llaman internamente a la rutina del parche. Al terminar continúan en la instrucción siguiente: no incluyen un retorno que termine tu rutina.
  • A, X e Y deben tratarse como temporales y quedan en 8 bits al volver. No se devuelve éxito o fallo en carry: el resultado son los colores escritos en el buffer de destino. Conservan DBR y D conforme a las reglas de estado del CPU.
  • Pueden sobrescribir $00-$0F, $45-$54, $6A, $8A-$8F y $D5-$D7, según la operación. Allí se preparan punteros, longitudes, canales y ratios; no guardes en ese espacio valores que deban sobrevivir a la llamada.
  • Los bancos de origen y destino se leen con A de 8 bits; las direcciones, offsets y cantidades de colores se leen con A de 16 bits durante la preparación. Los canales y ratios se leen con A de 8 bits. El ID de DoEffect se lee con A de 16 bits. Prepara los operandos de memoria con el tamaño correspondiente.
  • Si tus operandos están indexados, X e Y deben identificar sus datos al entrar. Su valor puede cambiar dentro de la llamada. Las variantes completas también deben evitar que sus argumentos se solapen con los temporales que se preparan antes de leerlos.

Preparar los colores: SetRGBBase y SetHSLBase

Antes de modificar los colores, necesitas una copia con la que calcular el efecto. %SetRGBBase() prepara esa copia para efectos RGB; %SetHSLBase() la prepara para HSL. Si los colores originales no cambiaron, puedes reutilizarla en los siguientes frames.

En las variantes Default solo indicas el primer color y cuántos colores quieres preparar:

%SetRGBBaseDefault(offset, length)
%SetHSLBaseDefault(offset, length)

offset es el número del primer color y length es la cantidad. Por ejemplo, #$0081 y #$000F seleccionan los 15 colores visibles de la paleta 8.

Si necesitas elegir tú las direcciones donde leer y guardar los colores, utiliza las versiones completas:

%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length)
%SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)

Las variantes %SetRGBBaseDefault(offset, length) y %SetHSLBaseDefault(offset, length) leen de DX_PPU_CGRAM_PaletteCopy y guardan el resultado en DX_PPU_CGRAM_BaseRGBPalette o DX_PPU_CGRAM_BaseHSLPalette.

Ejemplo: preparar una paleta de sprites

    ; Paleta 8, sin incluir su primer color transparente.
    %SetRGBBaseDefault(#$0081, #$000F)

    ; Para trabajar en HSL, utiliza esta variante en su lugar:
    ; %SetHSLBaseDefault(#$0081, #$000F)

$81 es el segundo color de la paleta 8: la paleta comienza en el color $80 y se procesan los 15 siguientes.

Mezclar colores: Mix y MixAndMerge

Estas macros acercan los colores originales a los valores que indiques. Por ejemplo, puedes llevar el rojo a 31 y el verde y azul a 0 para teñir de rojo una paleta. Al cambiar poco a poco los ratios, el efecto aparece gradualmente.

Los parámetros v indican el color que quieres alcanzar, entre 0 y 31. Los parámetros r indican cuánto acercarse a ese color: 0 conserva el original, 127 aplica el cambio completo y 64 lo aplica aproximadamente a la mitad. En los ejemplos se escriben como #$00, #$7F y #$40.

Para RGB, los valores 1, 2 y 3 corresponden a rojo, verde y azul. Para HSL corresponden a tono, saturación y luminosidad.

El final del nombre indica qué componentes se modifican:

RGB HSL Componentes modificados
R, G, B H, S, L Uno.
RG, RB, GB HS, HL, SL Dos.
RGB HSL Los tres.

Cada combinación está disponible como Mix..., MixAndMerge... y MixAndMerge...Default. Por ejemplo: %MixR(), %MixAndMergeR() y %MixAndMergeRDefault().

Primero se entregan los ratios de los componentes elegidos y después sus valores nuevos, en el orden del nombre. Al final van las direcciones de origen y destino, el primer color y la cantidad. Las variantes Default omiten las direcciones.

%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length)
%MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length)
%MixAndMergeLDefault(r3, v3, offset, length)

Ejemplo RGB: teñir de rojo

    ; Preparar los colores originales de la paleta 8.
    %SetRGBBaseDefault(#$0081, #$000F)

    ; Acercar los tres componentes a un rojo puro, aproximadamente a la mitad.
    %MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)

Los tres primeros valores #$40 indican la intensidad del cambio para rojo, verde y azul. Los siguientes, #$1F, #$00, #$00, indican el rojo puro al que se acercarán. Los dos últimos seleccionan los 15 colores de la paleta 8.

Ejemplo HSL: aclarar la paleta

    %SetHSLBaseDefault(#$0081, #$000F)
    %MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)

Aquí solo cambia la luminosidad: #$40 aplica aproximadamente la mitad del cambio y #$1F indica la luminosidad máxima. Este es un ejemplo independiente del anterior.

Cambiar entre paletas: PaletteTransition

Estas macros acercan cada color de la paleta original al color correspondiente de otra paleta. A diferencia de Mix, cada color tiene su propio destino. Sirven, por ejemplo, para pasar de los colores normales de un sprite a una paleta de daño.

Las variantes son PaletteTransitionRGB, PaletteTransitionHSL, PaletteTransitionRGBAndMerge y PaletteTransitionHSLAndMerge. Las dos variantes AndMerge también tienen versión Default.

%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)
%PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length)
%PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)

targetpal y targetpalbnk indican la dirección y el banco de la paleta de destino. Debe estar preparada con 3 bytes por color, en RGB o HSL según la macro. Los ratios controlan cuánto se acerca cada componente al color de destino.

Ejemplo: calcular un paso intermedio de una transición

    ; Este ejemplo trabaja con los primeros 15 colores de la copia de paletas.
    %SetRGBBaseDefault(#$0000, #$000F)
    %PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB>>16, #$0000, #$000F)

El ejemplo supone que !PaletteMyTargetRGB corresponde a una paleta de destino RGB generada al instalar un *.paleffect de transición. Su dirección queda en DXDefines.asm. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: my_target pasa a MyTarget. Para HSL se utiliza la paleta convertida a HSL y la macro correspondiente.

Aplicar un efecto de un archivo: DoEffect

%DoEffect() aplica un efecto de un archivo *.paleffect mediante su ID. El archivo ya contiene el tipo de efecto, los valores de color y los ratios, por lo que no necesitas entregarlos uno por uno.

%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length)
%DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length)
%DoEffectAndMergeDefaultRGB(effect, offset, length)
%DoEffectAndMergeDefaultHSL(effect, offset, length)
  • effect: ID del efecto, como #!PaletteEffectIDMyEffect0.
  • El origen debe contener colores RGB o HSL separados, según el efecto elegido.
  • DoEffect guarda el resultado con 3 bytes por color para poder seguir modificándolo.
  • DoEffectAndMerge guarda colores en formato de SNES. Las variantes DefaultRGB y DefaultHSL eligen la base correspondiente y escriben en DX_PPU_CGRAM_PaletteWriteMirror.

Ejemplo: aplicar un efecto RGB a la paleta 8

    %SetRGBBaseDefault(#$0081, #$000F)
    %DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)

!PaletteEffectIDMyEffect0 se genera desde un archivo *.paleffect y queda en DXDefines.asm. El nombre se normaliza en PascalCase eliminando separadores: my_effect pasa a MyEffect. El número final identifica el efecto dentro del archivo. Si el efecto trabaja en HSL, prepara la base HSL y utiliza %DoEffectAndMergeDefaultHSL().

Convertir entre RGB y HSL

%RGBToHSL() convierte colores RGB a HSL y %HSLToRGB() hace el cambio contrario. Ambas leen y escriben 3 bytes por color. Sirven cuando necesitas continuar modificando una paleta con un efecto que usa el otro sistema de color.

%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length)
%HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)

Ejemplo: convertir la base RGB a HSL

    %RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette>>16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette>>16, #$0081, #$000F)

El ejemplo lee los 15 colores de la paleta 8 de la base RGB y guarda su equivalente en la base HSL. La base RGB debe estar preparada antes de llamar a la conversión.

Combinar un efecto propio con el global

Registros y memoria temporal: estas dos macros entran con A de 16 bits, X de 8 bits con el valor de la paleta y Y de 8 bits con el resultado de la asignación sin carga. Al volver los tres quedan en 8 bits. Con sprite = 1, X se recupera desde !SpriteIndex; con sprite = 0, no se conserva X. A e Y pueden cambiar. Utilizan los temporales de efectos y $F0-$F3. Conservan DBR y D. A diferencia de las demás macros de efectos, incluyen RTL y devuelven disponibilidad mediante carry, también cuando reutilizan un resultado anterior.

%ConcatenateRGBPaletteEffectToGlobal() y %ConcatenateHSLPaletteEffectToGlobal() permiten aplicar un efecto propio a una paleta que también debe recibir el efecto global. Son las macros utilizadas por las llamadas para sprites del mismo nombre, pero permiten elegir las variables de paleta.

Suelen utilizarse después de %PaletteAssignmentNoUpload() o su variante para sprites: primero se asigna la paleta sin cargar los colores y después se aplican los efectos. Conserva los datos devueltos por la asignación para esta segunda llamada.

%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette)
%ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)
  • sprite: 1 recupera el índice del sprite desde !SpriteIndex; 0 permite utilizar variables propias.
  • paletteOption: variable o valor de las opciones de paleta; activa el bit $80 para incluir el efecto global.
  • palette: variable que contiene la paleta asignada, entre $00 y $0E de dos en dos.
  • A de 16 bits: ID del efecto local RGB o HSL, según la macro.
  • X de 8 bits: copia del valor de la paleta asignada.
  • Y de 8 bits: conserva el valor devuelto por la asignación sin carga.
  • $02-$04: dirección de los colores originales preparada por esa asignación.

Devuelven el carry activado si se puede dibujar con el efecto solicitado o con el anterior mientras se prepara el nuevo. Si todavía no hay un resultado disponible, el carry queda desactivado. Estas dos macros ya terminan la rutina con RTL.

Ejemplo: completar una asignación sin carga

; Llamar esta rutina con JSL después de asignar la paleta sin carga.
; Deben conservarse Y y $02-$04 de aquella llamada.
ApplyLocalEffect:
    LDA !NormalPalette,x
    TAX
    REP #$20
    LDA #!PaletteEffectIDMyEffect0
    %ConcatenateRGBPaletteEffectToGlobal(1, "!NormalPaletteOption,x", "!NormalPalette,x")

!PaletteEffectIDMyEffect0 se genera desde un *.paleffect y queda en DXDefines.asm. El nombre se normaliza en PascalCase eliminando separadores: my_effect pasa a MyEffect. Para un efecto HSL, utiliza la macro HSL. Si usas Y para leer una tabla de efectos, guarda su valor con PHY y recupéralo con PLY antes de concatenar.

Elegir las direcciones y combinar varios efectos

Las variantes Default de los ejemplos eligen las direcciones por ti. Si necesitas guardar los resultados en otro lugar o aplicar varios efectos seguidos, utiliza las versiones completas. Estos son los parámetros de dirección que aparecen en ellas:

  • src: dónde leer los colores originales; srcbnk: su banco.
  • dst: dónde guardar el resultado; dstbnk: su banco. El destino debe ser un espacio de RAM que tu código pueda utilizar.
  • offset: primer color que se procesará, contando desde 0.
  • length: cantidad de colores que se procesarán.

Para indicar una dirección fija, se utiliza #Nombre para la dirección y #Nombre>>16 para su banco, como en el ejemplo de conversión RGB a HSL. También puedes pasar variables que contengan esos datos.

El espacio necesario depende del paso que estés realizando:

Operación Lee Guarda
SetRGBBase / SetHSLBase Paleta normal: 2 bytes por color. Colores separados: 3 bytes por color.
Mix, PaletteTransition, DoEffect sin AndMerge Colores separados: 3 bytes por color. Colores separados: 3 bytes por color.
Variantes AndMerge Colores separados: 3 bytes por color. Paleta normal: 2 bytes por color.
RGBToHSL / HSLToRGB Colores separados: 3 bytes por color. Colores separados: 3 bytes por color.

Por ejemplo, si quieres aplicar dos efectos seguidos, el primero debe guardar sus colores separados, sin AndMerge. El segundo lee ese resultado y utiliza AndMerge para dejar la paleta lista para cargarla. Si uno trabaja en RGB y el otro en HSL, convierte los colores entre ambos pasos.

Las macros utilizan memoria temporal, entre otras las direcciones $45-$50, $51-$53, $6A, $8A, $8C, $8E, $0E-$0F y $D5-$D7, según la operación. No guardes en ellas datos que necesites conservar después de la llamada.

PPU

Estas macros permiten cargar gráficos en VRAM y colores en CGRAM. VRAM es la memoria donde SNES guarda los gráficos que muestra; CGRAM guarda sus paletas.

La llamada deja anotada una transferencia para el próximo NMI, cuando el juego puede actualizar esas memorias. No hace la copia inmediatamente. Los datos de origen deben seguir disponibles hasta que se realice la transferencia.

Qué llamada elegir

Necesitas… VRAM CGRAM
Indicar la dirección de origen y su banco por separado. TransferToVRAM TransferToCGRAM
Indicar una dirección completa y dejar que la macro obtenga el banco. TransferToVRAMFromAddr TransferToCGRAMFromAddr
Cargar un recurso completo registrado en Dynamic Xtreme. TransferResourceToVRAM TransferResourceToCGRAM
Cargar solo una cantidad de bytes de un recurso. TransferResourceToVRAMWithLenght TransferResourceToCGRAMWithLenght

Las versiones normales comprueban si la transferencia cabe dentro del límite de bytes del frame:

  • Carry activado: la transferencia quedó programada.
  • Carry desactivado: no se programó porque superaría ese límite. Tu código puede intentarlo en otro frame.

Este límite se comparte con las demás cargas de Dynamic Xtreme. Programar varias copias en un frame consume parte del mismo límite. Estas macros modifican A y X. Al aceptar la transferencia dejan A, X e Y en modo de 8 bits; si la rechazan, dejan A en 8 bits, pero no cambian necesariamente el modo de X e Y.

Límites y condiciones de las transferencias

Antes de preparar las entradas, ten en cuenta estos límites:

Presupuesto de bytes y capacidad de las listas

Límite Qué controla Valor predeterminado
DX_Dynamic_MaxDataPerFrame Cantidad total de bytes que se permite solicitar durante un frame. Se compara con DX_Dynamic_CurrentDataSend, que acumula los bytes solicitados por los distintos recursos. $0800 bytes, compartidos entre las cargas de Dynamic Xtreme.
Lista de VRAM Cantidad de solicitudes que caben en sus tablas. Cada entrada utiliza dos bytes por tabla; !VRAMTransferSize reserva la cantidad de bytes de cada una. !VRAMTransferSize = 64: espacio para 32 solicitudes.
Lista de CGRAM Cantidad de solicitudes que caben en sus tablas. !CGRAMTransferSize determina la cantidad de entradas disponibles. !CGRAMTransferSize = 64: espacio para 64 solicitudes.

Son límites diferentes. Por ejemplo, 32 transferencias de 2 bytes a VRAM solo solicitan 64 bytes, pero ya ocupan las 32 entradas de la lista predeterminada. No puedes añadir otra solo porque todavía quede presupuesto de bytes.

Las macros normales comprueban el presupuesto de bytes, pero no comprueban si queda una entrada libre en la lista. Si la lista está llena, debes posponer la solicitud desde tu código. Añadirla de todos modos puede escribir fuera de las tablas y corromper otras variables; no se devuelve un fallo específico por lista llena. Cuenta también las solicitudes de otros sistemas: una pose dinámica puede necesitar varias transferencias.

Las variantes Forced omiten la comprobación del presupuesto de bytes y suman la cantidad solicitada a DX_Dynamic_CurrentDataSend. No aumentan la capacidad de las listas ni el tiempo disponible para transferencias. Los contadores de las listas son de 8 bits y el de bytes es de 16 bits: no permitas que se desborden.

Condiciones que debe cumplir la transferencia

Dato Responsabilidad de tu código
Longitud Utiliza una cantidad de bytes mayor que cero y par. En DMA, $0000 significa 65536 bytes, no una copia vacía. Las macros de PPU no comprueban estas condiciones.
Origen La cantidad solicitada debe existir en el recurso o buffer y no debe cruzar el final de su banco. El DMA no continúa automáticamente en el banco siguiente. Divide la carga si necesitas cruzarlo.
Origen en RAM Debes conservar el contenido del buffer hasta que NMI ejecute la transferencia. La lista guarda su dirección, no una copia de los datos. En SA-1, utiliza memoria que también pueda leer el S-CPU, que realiza la transferencia.
Destino en VRAM La dirección se expresa en palabras de 2 bytes. Tanto el inicio como el final de la carga deben quedar dentro de $0000–$7FFF y en el espacio gráfico que tu recurso puede utilizar. Por ejemplo, $0200 bytes desde $6000 ocupan las palabras $6000–$60FF.
Destino en CGRAM El destino indica el primer color. Cada color ocupa 2 bytes; la carga no debe pasar del color $FF. Por ejemplo, desde $F1 caben 15 colores, es decir, $001E bytes.

El carry activado de una macro normal indica que aceptó la solicitud según el presupuesto de bytes; no confirma que haya validado el origen, el destino, la longitud o la capacidad de la lista. Estas condiciones también se aplican a las variantes Forced.

Para cambiar colores conservando las copias de paleta de SMW y el estado de los efectos, utiliza TransferPalette. Las transferencias de PPU a CGRAM solo programan la copia.

Estado de los registros

  • Entra con A, X e Y en 8 bits. Las versiones normales establecen internamente A de 16 bits para comprobar el presupuesto, pero este estado de entrada también permite utilizar las variantes Forced, especialmente las de CGRAM.
  • Al aceptar la transferencia, A y X cambian y los tres registros quedan en 8 bits. Y no se utiliza como registro de trabajo, pero pierde su byte alto si entrabas con índices de 16 bits. Al rechazarla, A cambia y queda en 8 bits; X e Y conservan sus valores y el tamaño que tenían al entrar.
  • No utilizan scratch para preparar la solicitud. Escriben en las listas de transferencias y en el contador de bytes del frame. Conservan DBR y D. DBR debe permitir acceder al contador; las variantes también pueden necesitar ese banco para leer los operandos de memoria que tú entregues.
  • Las direcciones de origen y las longitudes se leen con A de 16 bits. El destino de VRAM y su argumento de banco se leen con A de 16 bits; el banco debe proporcionarse como un valor de 16 bits cuyo byte alto sea cero. En CGRAM, el banco de origen y el color de destino se leen con A de 8 bits.
  • X cambia antes de leer varios argumentos. No pases direcciones indexadas con X suponiendo que conservará el índice del sprite. Prefiere inmediatos o variables independientes de X para los datos de la transferencia.
  • No incluyen RTS ni RTL. El código continúa después de la expansión. Comprueba el carry de las variantes normales antes de otra operación que lo modifique. Las variantes Forced no devuelven un indicador de éxito en carry.

Estas reglas también se aplican a las variantes FromAddr, Resource y WithLenght: preparan los argumentos y expanden la misma transferencia.

TransferToVRAM

%TransferToVRAM() programa una copia de gráficos desde ROM o RAM hacia VRAM.

%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)
  • VRAMOffset: dirección de destino en VRAM, expresada en palabras de 2 bytes. Por ejemplo, copiar $0200 bytes desde $6000 ocupa las palabras $6000-$60FF.
  • ResourceAddr: dirección de origen dentro de su banco.
  • ResourceBNK: banco del origen.
  • Lenght: cantidad de bytes que se copiarán. Se conserva esta escritura del nombre porque así aparece en la macro.

Ejemplo: programar la carga de gráficos

    %TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics>>16, #$0200)
    BCC .NotLoaded
    ; La copia se realizará en el próximo NMI.
.NotLoaded

!ResourceMyGraphics es la dirección de un recurso registrado desde un DynamicInfo; queda en DXDefines.asm. El nombre se normaliza eliminando espacios, guiones y guiones bajos y poniendo en mayúscula la inicial de cada palabra: my_graphics pasa a MyGraphics. La cantidad de bytes solicitada debe existir en ese recurso.

TransferToVRAMFromAddr

Hace la misma copia, pero recibe la dirección completa del origen. La macro separa su dirección y banco por ti.

%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)

addr se escribe sin #; los otros parámetros se entregan como en TransferToVRAM.

Ejemplo

    %TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)
    BCC .NotLoaded
.NotLoaded

!ResourceMyGraphics se genera desde un recurso del DynamicInfo y queda en DXDefines.asm. Su nombre se normaliza en PascalCase: my_graphics se convierte en MyGraphics.

TransferResourceToVRAM y TransferResourceToVRAMWithLenght

Estas variantes reciben el nombre de un recurso de Dynamic Xtreme. La primera copia el recurso completo; la segunda copia la cantidad de bytes que indiques.

%TransferResourceToVRAM(VRAMOffset, ResourceName)
%TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)

Para un recurso cuyos defines sean !ResourceMyGraphics y !ResourceMyGraphicsSize, escribe "MyGraphics" como ResourceName.

Ejemplo: cargar el recurso completo

    %TransferResourceToVRAM(#$6000, "MyGraphics")
    BCC .NotLoaded
.NotLoaded

Ejemplo: cargar solo sus primeros $0200 bytes

    %TransferResourceToVRAMWithLenght(#$6000, "MyGraphics", #$0200)
    BCC .NotLoaded
.NotLoaded

El nombre y el tamaño se obtienen de los defines generados en DXDefines.asm al instalar los recursos del DynamicInfo. Utiliza el nombre normalizado: my_graphics pasa a MyGraphics, eliminando los separadores y poniendo en mayúscula la inicial de cada palabra.

TransferToCGRAM

%TransferToCGRAM() programa una copia de colores desde ROM o RAM hacia una paleta de SNES.

%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)
  • CGRAMOffset: número del primer color de destino, entre $00 y $FF. Por ejemplo, la paleta 8 comienza en el color $80.
  • TableAddr y TableBNK: dirección y banco de los colores que se van a copiar.
  • Lenght: cantidad de bytes. Cada color ocupa 2 bytes; 15 colores ocupan $001E bytes.

Los colores de origen deben estar en formato normal de SNES, BGR555. Si calculaste un efecto, utiliza su resultado final de 2 bytes por color, como el que producen las variantes AndMerge.

Ejemplo: copiar los 15 colores visibles de la paleta 8

    %TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror>>16, #$001E)
    BCC .NotLoaded
.NotLoaded

Este ejemplo toma el resultado de un efecto guardado en DX_PPU_CGRAM_PaletteWriteMirror. El desplazamiento $0102 corresponde al color $81, porque cada color ocupa 2 bytes. Se omite el primer color de la paleta, que es transparente en sprites.

TransferToCGRAMFromAddr

Hace la misma copia de colores, pero recibe la dirección completa del origen. Escribe addr sin #.

%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)

Ejemplo

    %TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)
    BCC .NotLoaded
.NotLoaded

El resultado es el mismo que en el ejemplo anterior: programa la carga de 15 colores a partir del segundo color de la paleta 8.

TransferResourceToCGRAM y TransferResourceToCGRAMWithLenght

Estas variantes copian los colores de un recurso registrado en Dynamic Xtreme. La primera utiliza su tamaño completo; la segunda utiliza la cantidad de bytes que indiques.

%TransferResourceToCGRAM(CGRAMOffset, ResourceName)
%TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)

Ejemplo: copiar un recurso completo de colores

    %TransferResourceToCGRAM(#$80, "MyColors")
    BCC .NotLoaded
.NotLoaded

Ejemplo: copiar solo 15 colores

    %TransferResourceToCGRAMWithLenght(#$81, "MyColors", #$001E)
    BCC .NotLoaded
.NotLoaded

Estos ejemplos suponen un recurso general de colores con los defines !ResourceMyColors y !ResourceMyColorsSize, generados en DXDefines.asm desde un DynamicInfo. Utiliza el nombre normalizado: my_colors pasa a MyColors. En el segundo ejemplo, el recurso debe comenzar con los 15 colores que se quieren copiar, sin anteponer el color transparente.

Variantes Forced

Todas las transferencias anteriores tienen una variante cuyo nombre comienza con Forced. Programa la copia aunque supere el límite de bytes del frame. La cantidad copiada también se suma al total de ese frame.

VRAM CGRAM
ForcedTransferToVRAM ForcedTransferToCGRAM
ForcedTransferToVRAMFromAddr ForcedTransferToCGRAMFromAddr
ForcedTransferResourceToVRAM ForcedTransferResourceToCGRAM
ForcedTransferResourceToVRAMWithLenght ForcedTransferResourceToCGRAMWithLenght

Reciben los mismos parámetros que las versiones sin Forced. Su carry no indica si la transferencia fue aceptada. Prepara A en modo de 8 bits antes de utilizarlas; al terminar dejan A, X e Y en modo de 8 bits.

Ejemplo

    %ForcedTransferResourceToVRAM(#$6000, "MyGraphics")
    ; No se comprueba el carry en esta variante.

MyGraphics corresponde al recurso !ResourceMyGraphics de DXDefines.asm, generado desde el DynamicInfo. Se utiliza el nombre normalizado, como my_graphics → MyGraphics.

Utiliza Forced para cargas que deben tener prioridad y cuyo tamaño ya controlas. Si fuerzas demasiados datos, las copias pueden superar el tiempo disponible para actualizar los gráficos. En las demás cargas, utiliza las variantes normales y comprueba el carry.

Matemáticas

Estas macros multiplican y dividen números utilizando el hardware de SNES o SA-1, según la ROM. Utilizan números sin signo: los valores representan cantidades positivas o cero.

Prepara A en modo de 8 bits antes de llamarlas. Las macros no cambian por ti el tamaño de A, X o Y.

Registros y memoria temporal: todas las macros de esta categoría, incluidas W y After..., modifican A y N/Z, conservan X, Y, carry, DBR y D, y no utilizan scratch. Mantienen el tamaño de los registros con el que entraron; A debe estar en 8 bits para que las escrituras al hardware sean correctas. DBR debe permitir acceder a los registros aritméticos de SNES o SA-1, según corresponda. No incluyen RTS ni RTL; el código continúa después de la macro. El resultado está en los registros hardware indicados abajo, no en A. El carry no informa de éxito ni de desbordamiento del cálculo.

Cómo escribir los argumentos

Mul, Div, MulAfterMul y DivAfterDiv pegan el argumento directamente después de LDA. Escribe el argumento entre comillas con un espacio al principio: " #$05" produce LDA #$05.

También puedes comenzar el argumento con .b, .w o .l para elegir cómo se escribe el acceso a memoria. Por ejemplo, si $02 contiene el número que quieres multiplicar:

    %Mul(".b $02", " #$07")

Esto genera LDA.b $02 para leer el primer número y LDA #$07 para el segundo. Los sufijos eligen cómo se accede a la dirección; no cambian cuántos bits tiene A. La multiplicación sigue utilizando números de 8 bits.

Las variantes con W, además de MulAfterDiv y DivAfterMul, ya añaden un espacio antes de los argumentos. En ellas puedes escribir los valores normalmente, como %MulW(#$05, #$07). En la implementación actual no se pasan los sufijos .b, .w o .l de esta misma manera a esas variantes, porque el espacio que añaden quedaría entre LDA y el sufijo.

¿Qué significa la W?

El hardware necesita un pequeño tiempo para terminar el cálculo. Las macros con W incluyen esa espera: puedes leer el resultado inmediatamente después. Las versiones sin W permiten ejecutar otro código mientras se calcula, pero debes dejar pasar el tiempo necesario antes de leerlo. Si necesitas el resultado en la siguiente instrucción, utiliza la variante con W.

Los resultados se leen mediante estos defines:

  • !MultiplicationResult: resultado de multiplicar, de 16 bits.
  • !DivisionResult: cociente de la división, de 16 bits.
  • !RemainderResult: resto de la división, de 16 bits.

Estos defines ya seleccionan la dirección correspondiente a SNES o SA-1. El siguiente cálculo puede cambiar los resultados anteriores; guárdalos si los necesitas después.

Mul y MulW

Multiplican dos valores de 8 bits y producen un resultado de 16 bits.

%Mul(a, b)
%MulW(a, b)

a y b pueden ser valores inmediatos, como #$06, o variables de 8 bits.

Ejemplo: 6 × 7 = 42

    %MulW(#$06, #$07)
    REP #$20
    LDA !MultiplicationResult    ; A = $002A, es decir, 42
    SEP #$20

La llamada sin espera sería %Mul(" #$06", " #$07"). En ese caso no leas el resultado inmediatamente: ejecuta antes otro código que no utilice el hardware de multiplicación o división.

Div y DivW

Dividen un número de 16 bits por uno de 8 bits. El número de 16 bits se entrega separado en dos bytes: primero el alto y después el bajo.

%Div(ah, al, b)
%DivW(ah, al, b)
  • ah: byte alto del número que quieres dividir.
  • al: byte bajo del mismo número.
  • b: número por el que divides, entre 1 y 255.

Ejemplo: 300 ÷ 7 = 42, con resto 6

    ; 300 = $012C: byte alto $01, byte bajo $2C.
    %DivW(#$01, #$2C, #$07)

    REP #$20
    LDA !DivisionResult          ; A = $002A, es decir, 42
    LDA !RemainderResult         ; A = $0006
    SEP #$20

También puedes pasar una variable de 16 bits como dos argumentos: %DivW(MiNumero+1, MiNumero, #$07). MiNumero representa aquí una variable definida por tu código.

Continuar desde el resultado anterior

Las variantes AfterMul y AfterDiv toman el resultado del cálculo anterior como primer número. Solo debes indicar el segundo número.

Macro Cálculo que realiza
MulAfterMul(b) / MulWAfterMul(b) Toma los 8 bits bajos del resultado de la multiplicación anterior y los multiplica por b.
MulAfterDiv(b) / MulWAfterDiv(b) Toma los 8 bits bajos del cociente anterior y los multiplica por b.
DivAfterMul(b) / DivWAfterMul(b) Divide el resultado completo de la multiplicación anterior por b.
DivAfterDiv(b) / DivWAfterDiv(b) Divide el cociente completo de la división anterior por b.

La W sigue indicando que puedes leer el nuevo resultado inmediatamente después. Las variantes After... ya incluyen la espera que necesitan para tomar el resultado del cálculo anterior.

Ejemplo: dos multiplicaciones, (6 × 7) × 2 = 84

    %Mul(" #$06", " #$07")
    %MulWAfterMul(#$02)
    REP #$20
    LDA !MultiplicationResult    ; A = $0054, es decir, 84
    SEP #$20

Ejemplo: dividir y después multiplicar, (100 ÷ 4) × 3 = 75

    %Div(" #$00", " #$64", " #$04")
    %MulWAfterDiv(#$03)
    REP #$20
    LDA !MultiplicationResult    ; A = $004B, es decir, 75
    SEP #$20

Ejemplo: multiplicar y después dividir, (20 × 15) ÷ 4 = 75

    %Mul(" #$14", " #$0F")
    %DivWAfterMul(#$04)
    REP #$20
    LDA !DivisionResult          ; A = $004B, es decir, 75
    SEP #$20

Ejemplo: dos divisiones, (300 ÷ 3) ÷ 4 = 25

    %Div(" #$01", " #$2C", " #$03")
    %DivWAfterDiv(#$04)
    REP #$20
    LDA !DivisionResult          ; A = $0019, es decir, 25
    SEP #$20

En las multiplicaciones, el primer número siempre se limita a 8 bits. Si el resultado anterior era mayor que 255, MulAfterMul o MulAfterDiv solo utilizará su byte bajo. Las divisiones de esta tabla sí toman el resultado anterior completo, de 16 bits.